@tanstack/intent 0.0.21 → 0.0.27
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 +1 -2
- package/dist/cli.mjs +271 -300
- package/dist/display-DdmZXLZm.mjs +3 -0
- package/dist/index.d.mts +3 -3
- package/dist/index.mjs +6 -4
- package/dist/{install-prompt-C0M-U3WZ.mjs → install-BzDmD5yI.mjs} +12 -2
- package/dist/intent-library.mjs +7 -7
- package/dist/{library-scanner-CU3ZHPYU.mjs → library-scanner-B51qV5aX.mjs} +7 -5
- package/dist/library-scanner.d.mts +2 -2
- package/dist/library-scanner.mjs +2 -2
- package/dist/project-context-B7UXTA9F.mjs +53 -0
- package/dist/{scanner-SHzOJKcz.mjs → scanner-1ZGYK3Qm.mjs} +11 -5
- package/dist/scanner-CERQgrRN.mjs +5 -0
- package/dist/{setup-BNBVotfR.d.mts → setup-BA9RkENh.d.mts} +7 -13
- package/dist/{setup-J7F7DIP2.mjs → setup-BzhEoOBi.mjs} +34 -113
- package/dist/setup.d.mts +1 -1
- package/dist/setup.mjs +4 -2
- package/dist/{staleness-DZKvsLVq.mjs → staleness-BtmJtMpz.mjs} +1 -1
- package/dist/staleness-SRims-ZP.mjs +4 -0
- package/dist/{utils-BfjM1mQe.mjs → utils-COlDcU72.mjs} +8 -2
- package/dist/utils-dkVvY7D7.mjs +3 -0
- package/dist/workspace-patterns-Boa5mAbf.mjs +4 -0
- package/dist/workspace-patterns-BuJMfudb.mjs +98 -0
- package/package.json +3 -1
- package/dist/display-CuCDLPP_.mjs +0 -3
- package/dist/scanner-RWHFrJ_C.mjs +0 -5
- package/dist/staleness-Dr5-5wj5.mjs +0 -4
- package/dist/utils-D7OKi0Rn.mjs +0 -3
- /package/dist/{display-DhsUxNJW.mjs → display-hdsqb4w-.mjs} +0 -0
- /package/dist/{types-ddLtccfV.d.mts → types-BTQ9efv-.d.mts} +0 -0
package/dist/cli.mjs
CHANGED
|
@@ -1,35 +1,75 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import
|
|
2
|
+
import "./utils-COlDcU72.mjs";
|
|
3
|
+
import "./workspace-patterns-BuJMfudb.mjs";
|
|
4
|
+
import { t as resolveProjectContext } from "./project-context-B7UXTA9F.mjs";
|
|
5
|
+
import { n as runInstallCommand } from "./install-BzDmD5yI.mjs";
|
|
3
6
|
import { existsSync, readFileSync, readdirSync, realpathSync } from "node:fs";
|
|
4
|
-
import { dirname, join, relative, sep } from "node:path";
|
|
7
|
+
import { dirname, join, relative, resolve, sep } from "node:path";
|
|
5
8
|
import { fileURLToPath } from "node:url";
|
|
9
|
+
import { cac } from "cac";
|
|
6
10
|
|
|
7
|
-
//#region src/cli.ts
|
|
8
|
-
|
|
9
|
-
return join(dirname(fileURLToPath(import.meta.url)), "..", "meta");
|
|
10
|
-
}
|
|
11
|
+
//#region src/cli-error.ts
|
|
12
|
+
const CLI_FAILURE = Symbol("CliFailure");
|
|
11
13
|
function fail(message, exitCode = 1) {
|
|
12
14
|
throw {
|
|
15
|
+
[CLI_FAILURE]: true,
|
|
13
16
|
message,
|
|
14
17
|
exitCode
|
|
15
18
|
};
|
|
16
19
|
}
|
|
17
20
|
function isCliFailure(value) {
|
|
18
|
-
return !!value && typeof value === "object" &&
|
|
21
|
+
return !!value && typeof value === "object" && CLI_FAILURE in value;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
//#endregion
|
|
25
|
+
//#region src/cli-support.ts
|
|
26
|
+
function printWarnings(warnings) {
|
|
27
|
+
if (warnings.length === 0) return;
|
|
28
|
+
console.log("Warnings:");
|
|
29
|
+
for (const warning of warnings) console.log(` ⚠ ${warning}`);
|
|
30
|
+
}
|
|
31
|
+
function getMetaDir() {
|
|
32
|
+
return join(dirname(fileURLToPath(import.meta.url)), "..", "meta");
|
|
19
33
|
}
|
|
20
34
|
async function scanIntentsOrFail() {
|
|
21
|
-
const { scanForIntents } = await import("./scanner-
|
|
35
|
+
const { scanForIntents } = await import("./scanner-CERQgrRN.mjs");
|
|
22
36
|
try {
|
|
23
|
-
return
|
|
37
|
+
return scanForIntents();
|
|
24
38
|
} catch (err) {
|
|
25
|
-
fail(err.message);
|
|
39
|
+
fail(err instanceof Error ? err.message : String(err));
|
|
26
40
|
}
|
|
27
41
|
}
|
|
28
|
-
function
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
42
|
+
function readPackageName(root) {
|
|
43
|
+
try {
|
|
44
|
+
const pkgJson = JSON.parse(readFileSync(join(root, "package.json"), "utf8"));
|
|
45
|
+
return typeof pkgJson.name === "string" ? pkgJson.name : relative(process.cwd(), root) || "unknown";
|
|
46
|
+
} catch {
|
|
47
|
+
return relative(process.cwd(), root) || "unknown";
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
async function resolveStaleTargets(targetDir) {
|
|
51
|
+
const resolvedRoot = targetDir ? join(process.cwd(), targetDir) : process.cwd();
|
|
52
|
+
const { checkStaleness } = await import("./staleness-SRims-ZP.mjs");
|
|
53
|
+
if (existsSync(join(resolvedRoot, "skills"))) return { reports: [await checkStaleness(resolvedRoot, readPackageName(resolvedRoot))] };
|
|
54
|
+
const { findPackagesWithSkills, findWorkspaceRoot } = await import("./workspace-patterns-Boa5mAbf.mjs");
|
|
55
|
+
const workspaceRoot = findWorkspaceRoot(resolvedRoot);
|
|
56
|
+
if (workspaceRoot) {
|
|
57
|
+
const packageDirs = findPackagesWithSkills(workspaceRoot);
|
|
58
|
+
if (packageDirs.length > 0) return { reports: await Promise.all(packageDirs.map((packageDir) => checkStaleness(packageDir, readPackageName(packageDir)))) };
|
|
59
|
+
}
|
|
60
|
+
const staleResult = await scanIntentsOrFail();
|
|
61
|
+
return { reports: await Promise.all(staleResult.packages.map((pkg) => checkStaleness(pkg.packageRoot, pkg.name))) };
|
|
32
62
|
}
|
|
63
|
+
|
|
64
|
+
//#endregion
|
|
65
|
+
//#region src/commands/edit-package-json.ts
|
|
66
|
+
async function runEditPackageJsonCommand(root) {
|
|
67
|
+
const { runEditPackageJsonAll } = await import("./setup.mjs");
|
|
68
|
+
runEditPackageJsonAll(root);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
//#endregion
|
|
72
|
+
//#region src/commands/list.ts
|
|
33
73
|
function formatScanCoverage(result) {
|
|
34
74
|
const coverage = [];
|
|
35
75
|
if (result.nodeModules.local.scanned) coverage.push("project node_modules");
|
|
@@ -49,24 +89,10 @@ function printVersionConflicts(result) {
|
|
|
49
89
|
console.log();
|
|
50
90
|
}
|
|
51
91
|
}
|
|
52
|
-
function
|
|
53
|
-
const
|
|
54
|
-
|
|
55
|
-
|
|
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}`);
|
|
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();
|
|
69
|
-
if (jsonOutput) {
|
|
92
|
+
async function runListCommand(options, scanIntentsOrFail$1) {
|
|
93
|
+
const { computeSkillNameWidth, printSkillTree, printTable } = await import("./display-DdmZXLZm.mjs");
|
|
94
|
+
const result = await scanIntentsOrFail$1();
|
|
95
|
+
if (options.json) {
|
|
70
96
|
console.log(JSON.stringify(result, null, 2));
|
|
71
97
|
return;
|
|
72
98
|
}
|
|
@@ -80,7 +106,7 @@ async function cmdList(args) {
|
|
|
80
106
|
}
|
|
81
107
|
return;
|
|
82
108
|
}
|
|
83
|
-
const totalSkills = result.packages.reduce((sum,
|
|
109
|
+
const totalSkills = result.packages.reduce((sum, pkg) => sum + pkg.skills.length, 0);
|
|
84
110
|
console.log(`\n${result.packages.length} intent-enabled packages, ${totalSkills} skills (${result.packageManager})\n`);
|
|
85
111
|
if (scanCoverage) console.log(`Scanned: ${scanCoverage}${result.nodeModules.global.scanned ? " (local packages take precedence)" : ""}\n`);
|
|
86
112
|
printTable([
|
|
@@ -95,8 +121,8 @@ async function cmdList(args) {
|
|
|
95
121
|
pkg.intent.requires?.join(", ") || "–"
|
|
96
122
|
]));
|
|
97
123
|
printVersionConflicts(result);
|
|
98
|
-
const nameWidth = computeSkillNameWidth(result.packages.map((
|
|
99
|
-
const showTypes = result.packages.some((
|
|
124
|
+
const nameWidth = computeSkillNameWidth(result.packages.map((pkg) => pkg.skills));
|
|
125
|
+
const showTypes = result.packages.some((pkg) => pkg.skills.some((skill) => skill.type));
|
|
100
126
|
console.log(`\nSkills:\n`);
|
|
101
127
|
for (const pkg of result.packages) {
|
|
102
128
|
console.log(` ${pkg.name}`);
|
|
@@ -106,18 +132,18 @@ async function cmdList(args) {
|
|
|
106
132
|
});
|
|
107
133
|
console.log();
|
|
108
134
|
}
|
|
109
|
-
console.log(
|
|
110
|
-
console.log(
|
|
111
|
-
console.log(
|
|
135
|
+
console.log("Feedback:");
|
|
136
|
+
console.log(" Submit feedback on skill usage to help maintainers improve the skills.");
|
|
137
|
+
console.log(" Load: node_modules/@tanstack/intent/meta/feedback-collection/SKILL.md");
|
|
112
138
|
console.log();
|
|
113
139
|
printWarnings(result.warnings);
|
|
114
140
|
}
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
141
|
+
|
|
142
|
+
//#endregion
|
|
143
|
+
//#region src/commands/meta.ts
|
|
144
|
+
async function runMetaCommand(name, metaDir) {
|
|
118
145
|
if (!existsSync(metaDir)) fail("Meta-skills directory not found.");
|
|
119
|
-
if (
|
|
120
|
-
const name = args[0];
|
|
146
|
+
if (name) {
|
|
121
147
|
if (name.includes("..") || name.includes("/") || name.includes("\\")) fail(`Invalid meta-skill name: "${name}"`);
|
|
122
148
|
const skillFile = join(metaDir, name, "SKILL.md");
|
|
123
149
|
if (!existsSync(skillFile)) fail(`Meta-skill "${name}" not found. Run \`intent meta\` to list available meta-skills.`);
|
|
@@ -128,7 +154,8 @@ async function cmdMeta(args) {
|
|
|
128
154
|
}
|
|
129
155
|
return;
|
|
130
156
|
}
|
|
131
|
-
const
|
|
157
|
+
const { parseFrontmatter } = await import("./utils-dkVvY7D7.mjs");
|
|
158
|
+
const entries = readdirSync(metaDir, { withFileTypes: true }).filter((entry) => entry.isDirectory()).filter((entry) => existsSync(join(metaDir, entry.name, "SKILL.md")));
|
|
132
159
|
if (entries.length === 0) {
|
|
133
160
|
console.log("No meta-skills found.");
|
|
134
161
|
return;
|
|
@@ -138,14 +165,133 @@ async function cmdMeta(args) {
|
|
|
138
165
|
const fm = parseFrontmatter(join(metaDir, entry.name, "SKILL.md"));
|
|
139
166
|
let description = "";
|
|
140
167
|
if (typeof fm?.description === "string") description = fm.description.replace(/\s+/g, " ").trim();
|
|
141
|
-
const shortDesc = description.length > 60 ? description.slice(0, 57)
|
|
168
|
+
const shortDesc = description.length > 60 ? `${description.slice(0, 57)}...` : description;
|
|
142
169
|
console.log(` ${entry.name.padEnd(28)} ${shortDesc}`);
|
|
143
170
|
}
|
|
144
|
-
console.log(
|
|
145
|
-
console.log(
|
|
171
|
+
console.log("\nUsage: load the SKILL.md into your AI agent conversation.");
|
|
172
|
+
console.log("Path: node_modules/@tanstack/intent/meta/<name>/SKILL.md");
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
//#endregion
|
|
176
|
+
//#region src/commands/scaffold.ts
|
|
177
|
+
function runScaffoldCommand(metaDir) {
|
|
178
|
+
function metaSkillPath(name) {
|
|
179
|
+
return join(metaDir, name, "SKILL.md");
|
|
180
|
+
}
|
|
181
|
+
const prompt = `You are helping a library maintainer scaffold Intent skills.
|
|
182
|
+
|
|
183
|
+
Run the three meta skills below **one at a time, in order**. For each step:
|
|
184
|
+
1. Load the SKILL.md file specified
|
|
185
|
+
2. Follow its instructions completely
|
|
186
|
+
3. Present outputs to the maintainer for review
|
|
187
|
+
4. Do NOT proceed to the next step until the maintainer confirms
|
|
188
|
+
|
|
189
|
+
## Before you start
|
|
190
|
+
|
|
191
|
+
Gather this context yourself (do not ask the maintainer — agents should never
|
|
192
|
+
ask for information they can discover):
|
|
193
|
+
1. Read package.json for library name, repository URL, and homepage/docs URL
|
|
194
|
+
2. Detect if this is a monorepo (look for workspaces field, packages/ directory, lerna.json)
|
|
195
|
+
3. Use skills/ as the default skills root
|
|
196
|
+
4. For monorepos:
|
|
197
|
+
- Domain map artifacts go at the REPO ROOT: _artifacts/
|
|
198
|
+
- Skills go INSIDE EACH PACKAGE: packages/<pkg>/skills/
|
|
199
|
+
- Identify which packages are client-facing (usually client SDKs and primary framework adapters)
|
|
200
|
+
|
|
201
|
+
---
|
|
202
|
+
|
|
203
|
+
## Step 1 — Domain Discovery
|
|
204
|
+
|
|
205
|
+
Load and follow: ${metaSkillPath("domain-discovery")}
|
|
206
|
+
|
|
207
|
+
This produces: domain_map.yaml and skill_spec.md in the artifacts directory.
|
|
208
|
+
Domain discovery covers the WHOLE library (one domain map even for monorepos).
|
|
209
|
+
|
|
210
|
+
**STOP. Review outputs with the maintainer before continuing.**
|
|
211
|
+
|
|
212
|
+
---
|
|
213
|
+
|
|
214
|
+
## Step 2 — Tree Generator
|
|
215
|
+
|
|
216
|
+
Load and follow: ${metaSkillPath("tree-generator")}
|
|
217
|
+
|
|
218
|
+
This produces: skill_tree.yaml in the artifacts directory.
|
|
219
|
+
For monorepos, each skill entry should include a \`package\` field.
|
|
220
|
+
|
|
221
|
+
**STOP. Review outputs with the maintainer before continuing.**
|
|
222
|
+
|
|
223
|
+
---
|
|
224
|
+
|
|
225
|
+
## Step 3 — Generate Skills
|
|
226
|
+
|
|
227
|
+
Load and follow: ${metaSkillPath("generate-skill")}
|
|
228
|
+
|
|
229
|
+
This produces: individual SKILL.md files.
|
|
230
|
+
- Single-repo: skills/<domain>/<skill>/SKILL.md
|
|
231
|
+
- Monorepo: packages/<pkg>/skills/<domain>/<skill>/SKILL.md
|
|
232
|
+
|
|
233
|
+
---
|
|
234
|
+
|
|
235
|
+
## After all skills are generated
|
|
236
|
+
|
|
237
|
+
1. Run \`intent validate\` in each package directory
|
|
238
|
+
2. Commit skills/ and artifacts
|
|
239
|
+
3. For each publishable package, run: \`npx @tanstack/intent edit-package-json\`
|
|
240
|
+
4. Ensure each package has \`@tanstack/intent\` as a devDependency
|
|
241
|
+
5. Create a \`skill:<skill-name>\` label on the GitHub repo for each skill (use \`gh label create\`)
|
|
242
|
+
6. Add a README note: "If you use an AI agent, run \`npx @tanstack/intent@latest install\`"
|
|
243
|
+
`;
|
|
244
|
+
console.log(prompt);
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
//#endregion
|
|
248
|
+
//#region src/commands/setup-github-actions.ts
|
|
249
|
+
async function runSetupGithubActionsCommand(root, metaDir) {
|
|
250
|
+
const { runSetupGithubActions } = await import("./setup.mjs");
|
|
251
|
+
runSetupGithubActions(root, metaDir);
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
//#endregion
|
|
255
|
+
//#region src/commands/stale.ts
|
|
256
|
+
async function runStaleCommand(targetDir, options, resolveStaleTargets$1) {
|
|
257
|
+
const { reports } = await resolveStaleTargets$1(targetDir);
|
|
258
|
+
if (reports.length === 0) {
|
|
259
|
+
console.log("No intent-enabled packages found.");
|
|
260
|
+
return;
|
|
261
|
+
}
|
|
262
|
+
if (options.json) {
|
|
263
|
+
console.log(JSON.stringify(reports, null, 2));
|
|
264
|
+
return;
|
|
265
|
+
}
|
|
266
|
+
for (const report of reports) {
|
|
267
|
+
const driftLabel = report.versionDrift ? ` [${report.versionDrift} drift]` : "";
|
|
268
|
+
const vLabel = report.skillVersion && report.currentVersion ? ` (${report.skillVersion} → ${report.currentVersion})` : "";
|
|
269
|
+
console.log(`${report.library}${vLabel}${driftLabel}`);
|
|
270
|
+
const stale = report.skills.filter((skill) => skill.needsReview);
|
|
271
|
+
if (stale.length === 0) console.log(" All skills up-to-date");
|
|
272
|
+
else for (const skill of stale) console.log(` ⚠ ${skill.name}: ${skill.reasons.join(", ")}`);
|
|
273
|
+
console.log();
|
|
274
|
+
}
|
|
146
275
|
}
|
|
147
|
-
|
|
148
|
-
|
|
276
|
+
|
|
277
|
+
//#endregion
|
|
278
|
+
//#region src/commands/validate.ts
|
|
279
|
+
function buildValidationFailure(errors, warnings) {
|
|
280
|
+
const lines = [
|
|
281
|
+
"",
|
|
282
|
+
`❌ Validation failed with ${errors.length} error(s):`,
|
|
283
|
+
""
|
|
284
|
+
];
|
|
285
|
+
for (const { file, message } of errors) lines.push(` ${file}: ${message}`);
|
|
286
|
+
if (warnings.length > 0) {
|
|
287
|
+
lines.push("", "⚠ Packaging warnings:");
|
|
288
|
+
for (const warning of warnings) lines.push(` ${warning}`);
|
|
289
|
+
}
|
|
290
|
+
return lines.join("\n");
|
|
291
|
+
}
|
|
292
|
+
function collectPackagingWarnings(context) {
|
|
293
|
+
if (!context.packageRoot || !context.targetPackageJsonPath) return [];
|
|
294
|
+
const pkgJsonPath = context.targetPackageJsonPath;
|
|
149
295
|
if (!existsSync(pkgJsonPath)) return [];
|
|
150
296
|
let pkgJson;
|
|
151
297
|
try {
|
|
@@ -160,60 +306,18 @@ function collectPackagingWarnings(root) {
|
|
|
160
306
|
const files = pkgJson.files;
|
|
161
307
|
if (Array.isArray(files)) {
|
|
162
308
|
if (!files.includes("skills")) warnings.push("\"skills\" is not in the \"files\" array — skills won't be published");
|
|
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");
|
|
309
|
+
if (!context.isMonorepo && !files.includes("!skills/_artifacts")) warnings.push("\"!skills/_artifacts\" is not in the \"files\" array — artifacts will be published unnecessarily");
|
|
179
310
|
}
|
|
180
311
|
return warnings;
|
|
181
312
|
}
|
|
182
|
-
function
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
}
|
|
191
|
-
function readPackageName(root) {
|
|
192
|
-
try {
|
|
193
|
-
const pkgJson = JSON.parse(readFileSync(join(root, "package.json"), "utf8"));
|
|
194
|
-
return typeof pkgJson.name === "string" ? pkgJson.name : relative(process.cwd(), root) || "unknown";
|
|
195
|
-
} catch {
|
|
196
|
-
return relative(process.cwd(), root) || "unknown";
|
|
197
|
-
}
|
|
198
|
-
}
|
|
199
|
-
async function resolveStaleTargets(targetDir) {
|
|
200
|
-
const resolvedRoot = targetDir ? join(process.cwd(), targetDir) : process.cwd();
|
|
201
|
-
const { checkStaleness } = await import("./staleness-Dr5-5wj5.mjs");
|
|
202
|
-
if (existsSync(join(resolvedRoot, "skills"))) return { reports: [await checkStaleness(resolvedRoot, readPackageName(resolvedRoot))] };
|
|
203
|
-
const { findPackagesWithSkills, findWorkspaceRoot } = await import("./setup.mjs");
|
|
204
|
-
const workspaceRoot = findWorkspaceRoot(resolvedRoot);
|
|
205
|
-
if (workspaceRoot) {
|
|
206
|
-
const packageDirs = findPackagesWithSkills(workspaceRoot);
|
|
207
|
-
if (packageDirs.length > 0) return { reports: await Promise.all(packageDirs.map((packageDir) => checkStaleness(packageDir, readPackageName(packageDir)))) };
|
|
208
|
-
}
|
|
209
|
-
const staleResult = await scanIntentsOrFail();
|
|
210
|
-
return { reports: await Promise.all(staleResult.packages.map((pkg) => checkStaleness(pkg.packageRoot, pkg.name))) };
|
|
211
|
-
}
|
|
212
|
-
async function cmdValidate(args) {
|
|
213
|
-
const [{ parse: parseYaml }, { findSkillFiles }] = await Promise.all([import("yaml"), import("./utils-D7OKi0Rn.mjs")]);
|
|
214
|
-
const targetDir = args[0] ?? "skills";
|
|
215
|
-
const skillsDir = join(process.cwd(), targetDir);
|
|
216
|
-
const packageRoot = resolvePackageRoot(skillsDir);
|
|
313
|
+
async function runValidateCommand(dir) {
|
|
314
|
+
const [{ parse: parseYaml }, { findSkillFiles }] = await Promise.all([import("yaml"), import("./utils-dkVvY7D7.mjs")]);
|
|
315
|
+
const targetDir = dir ?? "skills";
|
|
316
|
+
const context = resolveProjectContext({
|
|
317
|
+
cwd: process.cwd(),
|
|
318
|
+
targetPath: targetDir
|
|
319
|
+
});
|
|
320
|
+
const skillsDir = context.targetSkillsDir ?? resolve(process.cwd(), targetDir);
|
|
217
321
|
if (!existsSync(skillsDir)) fail(`Skills directory not found: ${skillsDir}`);
|
|
218
322
|
const errors = [];
|
|
219
323
|
const skillFiles = findSkillFiles(skillsDir);
|
|
@@ -239,10 +343,11 @@ async function cmdValidate(args) {
|
|
|
239
343
|
let fm;
|
|
240
344
|
try {
|
|
241
345
|
fm = parseYaml(match[1]);
|
|
242
|
-
} catch {
|
|
346
|
+
} catch (err) {
|
|
347
|
+
const detail = err instanceof Error ? err.message : String(err);
|
|
243
348
|
errors.push({
|
|
244
349
|
file: rel,
|
|
245
|
-
message:
|
|
350
|
+
message: `Invalid YAML frontmatter: ${detail}`
|
|
246
351
|
});
|
|
247
352
|
continue;
|
|
248
353
|
}
|
|
@@ -276,7 +381,7 @@ async function cmdValidate(args) {
|
|
|
276
381
|
});
|
|
277
382
|
}
|
|
278
383
|
const artifactsDir = join(skillsDir, "_artifacts");
|
|
279
|
-
if (existsSync(artifactsDir)) for (const fileName of [
|
|
384
|
+
if (!context.isMonorepo && existsSync(artifactsDir)) for (const fileName of [
|
|
280
385
|
"domain_map.yaml",
|
|
281
386
|
"skill_spec.md",
|
|
282
387
|
"skill_tree.yaml"
|
|
@@ -299,224 +404,90 @@ async function cmdValidate(args) {
|
|
|
299
404
|
}
|
|
300
405
|
if (fileName.endsWith(".yaml")) try {
|
|
301
406
|
parseYaml(content);
|
|
302
|
-
} catch {
|
|
407
|
+
} catch (err) {
|
|
408
|
+
const detail = err instanceof Error ? err.message : String(err);
|
|
303
409
|
errors.push({
|
|
304
410
|
file: relative(process.cwd(), artifactPath),
|
|
305
|
-
message:
|
|
411
|
+
message: `Invalid YAML in artifact file: ${detail}`
|
|
306
412
|
});
|
|
307
413
|
}
|
|
308
414
|
}
|
|
309
|
-
const warnings = collectPackagingWarnings(
|
|
415
|
+
const warnings = collectPackagingWarnings(context);
|
|
310
416
|
if (errors.length > 0) fail(buildValidationFailure(errors, warnings));
|
|
311
417
|
console.log(`✅ Validated ${skillFiles.length} skill files — all passed`);
|
|
312
418
|
if (warnings.length > 0) console.log();
|
|
313
419
|
printWarnings(warnings);
|
|
314
420
|
}
|
|
315
|
-
function cmdScaffold() {
|
|
316
|
-
const metaDir = getMetaDir();
|
|
317
|
-
const metaSkillPath = (name) => join(metaDir, name, "SKILL.md");
|
|
318
|
-
const prompt = `You are helping a library maintainer scaffold Intent skills.
|
|
319
|
-
|
|
320
|
-
Run the three meta skills below **one at a time, in order**. For each step:
|
|
321
|
-
1. Load the SKILL.md file specified
|
|
322
|
-
2. Follow its instructions completely
|
|
323
|
-
3. Present outputs to the maintainer for review
|
|
324
|
-
4. Do NOT proceed to the next step until the maintainer confirms
|
|
325
|
-
|
|
326
|
-
## Before you start
|
|
327
|
-
|
|
328
|
-
Gather this context yourself (do not ask the maintainer — agents should never
|
|
329
|
-
ask for information they can discover):
|
|
330
|
-
1. Read package.json for library name, repository URL, and homepage/docs URL
|
|
331
|
-
2. Detect if this is a monorepo (look for workspaces field, packages/ directory, lerna.json)
|
|
332
|
-
3. Use skills/ as the default skills root
|
|
333
|
-
4. For monorepos:
|
|
334
|
-
- Domain map artifacts go at the REPO ROOT: _artifacts/
|
|
335
|
-
- Skills go INSIDE EACH PACKAGE: packages/<pkg>/skills/
|
|
336
|
-
- Identify which packages are client-facing (usually client SDKs and primary framework adapters)
|
|
337
|
-
|
|
338
|
-
---
|
|
339
|
-
|
|
340
|
-
## Step 1 — Domain Discovery
|
|
341
|
-
|
|
342
|
-
Load and follow: ${metaSkillPath("domain-discovery")}
|
|
343
|
-
|
|
344
|
-
This produces: domain_map.yaml and skill_spec.md in the artifacts directory.
|
|
345
|
-
Domain discovery covers the WHOLE library (one domain map even for monorepos).
|
|
346
|
-
|
|
347
|
-
**STOP. Review outputs with the maintainer before continuing.**
|
|
348
|
-
|
|
349
|
-
---
|
|
350
|
-
|
|
351
|
-
## Step 2 — Tree Generator
|
|
352
|
-
|
|
353
|
-
Load and follow: ${metaSkillPath("tree-generator")}
|
|
354
|
-
|
|
355
|
-
This produces: skill_tree.yaml in the artifacts directory.
|
|
356
|
-
For monorepos, each skill entry should include a \`package\` field.
|
|
357
|
-
|
|
358
|
-
**STOP. Review outputs with the maintainer before continuing.**
|
|
359
|
-
|
|
360
|
-
---
|
|
361
|
-
|
|
362
|
-
## Step 3 — Generate Skills
|
|
363
|
-
|
|
364
|
-
Load and follow: ${metaSkillPath("generate-skill")}
|
|
365
|
-
|
|
366
|
-
This produces: individual SKILL.md files.
|
|
367
|
-
- Single-repo: skills/<domain>/<skill>/SKILL.md
|
|
368
|
-
- Monorepo: packages/<pkg>/skills/<domain>/<skill>/SKILL.md
|
|
369
|
-
|
|
370
|
-
---
|
|
371
|
-
|
|
372
|
-
## After all skills are generated
|
|
373
|
-
|
|
374
|
-
1. Run \`intent validate\` in each package directory
|
|
375
|
-
2. Commit skills/ and artifacts
|
|
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\`"
|
|
380
|
-
`;
|
|
381
|
-
console.log(prompt);
|
|
382
|
-
}
|
|
383
|
-
const USAGE = `TanStack Intent CLI
|
|
384
|
-
|
|
385
|
-
Usage:
|
|
386
|
-
intent list [--json] Discover intent-enabled packages
|
|
387
|
-
intent meta [name] List meta-skills, or print one by name
|
|
388
|
-
intent validate [<dir>] Validate skill files (default: skills/)
|
|
389
|
-
intent install Print a skill that guides your coding agent to set up skill-to-task mappings
|
|
390
|
-
intent scaffold Print maintainer scaffold prompt
|
|
391
|
-
intent edit-package-json Wire package.json (files, keywords) for skill publishing
|
|
392
|
-
intent setup-github-actions Copy CI workflow templates to .github/workflows/
|
|
393
|
-
intent stale [dir] [--json] Check skills for staleness`;
|
|
394
|
-
const HELP_BY_COMMAND = {
|
|
395
|
-
list: `${USAGE}
|
|
396
|
-
|
|
397
|
-
Examples:
|
|
398
|
-
intent list
|
|
399
|
-
intent list --json`,
|
|
400
|
-
meta: `intent meta [name]
|
|
401
|
-
|
|
402
|
-
List shipped meta-skills, or print a single meta-skill by name.
|
|
403
|
-
|
|
404
|
-
Examples:
|
|
405
|
-
intent meta
|
|
406
|
-
intent meta domain-discovery`,
|
|
407
|
-
validate: `intent validate [dir]
|
|
408
|
-
|
|
409
|
-
Validate SKILL.md files in the target directory.
|
|
410
|
-
|
|
411
|
-
Examples:
|
|
412
|
-
intent validate
|
|
413
|
-
intent validate packages/query/skills`,
|
|
414
|
-
install: `intent install
|
|
415
|
-
|
|
416
|
-
Print the install prompt used to set up skill-to-task mappings.`,
|
|
417
|
-
scaffold: `intent scaffold
|
|
418
|
-
|
|
419
|
-
Print the guided maintainer prompt for generating skills.`,
|
|
420
|
-
stale: `intent stale [dir] [--json]
|
|
421
421
|
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
}
|
|
445
|
-
|
|
422
|
+
//#endregion
|
|
423
|
+
//#region src/cli.ts
|
|
424
|
+
function createCli() {
|
|
425
|
+
const cli = cac("intent");
|
|
426
|
+
cli.usage("<command> [options]");
|
|
427
|
+
cli.command("list", "Discover intent-enabled packages").usage("list [--json]").option("--json", "Output JSON").example("list").example("list --json").action(async (options) => {
|
|
428
|
+
await runListCommand(options, scanIntentsOrFail);
|
|
429
|
+
});
|
|
430
|
+
cli.command("meta [name]", "List meta-skills, or print one by name").usage("meta [name]").example("meta").example("meta domain-discovery").action(async (name) => {
|
|
431
|
+
await runMetaCommand(name, getMetaDir());
|
|
432
|
+
});
|
|
433
|
+
cli.command("validate [dir]", "Validate skill files").usage("validate [dir]").example("validate").example("validate packages/query/skills").action(async (dir) => {
|
|
434
|
+
await runValidateCommand(dir);
|
|
435
|
+
});
|
|
436
|
+
cli.command("install", "Print a skill that guides your coding agent to set up skill-to-task mappings").usage("install").action(() => {
|
|
437
|
+
runInstallCommand();
|
|
438
|
+
});
|
|
439
|
+
cli.command("scaffold", "Print maintainer scaffold prompt").usage("scaffold").action(() => {
|
|
440
|
+
runScaffoldCommand(getMetaDir());
|
|
441
|
+
});
|
|
442
|
+
cli.command("stale [dir]", "Check skills for staleness").usage("stale [dir] [--json]").option("--json", "Output JSON").example("stale").example("stale packages/query").example("stale --json").action(async (targetDir, options) => {
|
|
443
|
+
await runStaleCommand(targetDir, options, resolveStaleTargets);
|
|
444
|
+
});
|
|
445
|
+
cli.command("edit-package-json", "Update package.json files so skills are published").usage("edit-package-json").action(async () => {
|
|
446
|
+
await runEditPackageJsonCommand(process.cwd());
|
|
447
|
+
});
|
|
448
|
+
cli.command("setup-github-actions", "Copy Intent CI workflow templates into .github/workflows/").usage("setup-github-actions").action(async () => {
|
|
449
|
+
await runSetupGithubActionsCommand(process.cwd(), getMetaDir());
|
|
450
|
+
});
|
|
451
|
+
cli.command("help [command]", "Display help for a command").action((commandName) => {
|
|
452
|
+
if (!commandName) {
|
|
453
|
+
cli.outputHelp();
|
|
454
|
+
return;
|
|
455
|
+
}
|
|
456
|
+
const command = cli.commands.find((candidate) => candidate.isMatched(commandName));
|
|
457
|
+
if (!command) fail(`Unknown command: ${commandName}`);
|
|
458
|
+
command.outputHelp();
|
|
459
|
+
});
|
|
460
|
+
cli.help();
|
|
461
|
+
return cli;
|
|
446
462
|
}
|
|
447
463
|
async function main(argv = process.argv.slice(2)) {
|
|
448
|
-
const command = argv[0];
|
|
449
|
-
const commandArgs = argv.slice(1);
|
|
450
464
|
try {
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
}
|
|
455
|
-
if (command === "help") {
|
|
456
|
-
printHelp(commandArgs[0]);
|
|
465
|
+
const cli = createCli();
|
|
466
|
+
if (argv.length === 0) {
|
|
467
|
+
cli.outputHelp();
|
|
457
468
|
return 0;
|
|
458
469
|
}
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
await cmdMeta(commandArgs);
|
|
469
|
-
return 0;
|
|
470
|
-
case "validate":
|
|
471
|
-
await cmdValidate(commandArgs);
|
|
472
|
-
return 0;
|
|
473
|
-
case "install":
|
|
474
|
-
console.log(INSTALL_PROMPT);
|
|
475
|
-
return 0;
|
|
476
|
-
case "scaffold":
|
|
477
|
-
cmdScaffold();
|
|
478
|
-
return 0;
|
|
479
|
-
case "stale": {
|
|
480
|
-
const jsonStale = commandArgs.includes("--json");
|
|
481
|
-
const { reports } = await resolveStaleTargets(commandArgs.find((arg) => !arg.startsWith("-")));
|
|
482
|
-
if (reports.length === 0) {
|
|
483
|
-
console.log("No intent-enabled packages found.");
|
|
484
|
-
return 0;
|
|
485
|
-
}
|
|
486
|
-
if (jsonStale) {
|
|
487
|
-
console.log(JSON.stringify(reports, null, 2));
|
|
488
|
-
return 0;
|
|
489
|
-
}
|
|
490
|
-
for (const report of reports) {
|
|
491
|
-
const driftLabel = report.versionDrift ? ` [${report.versionDrift} drift]` : "";
|
|
492
|
-
const vLabel = report.skillVersion && report.currentVersion ? ` (${report.skillVersion} → ${report.currentVersion})` : "";
|
|
493
|
-
console.log(`${report.library}${vLabel}${driftLabel}`);
|
|
494
|
-
const stale = report.skills.filter((s) => s.needsReview);
|
|
495
|
-
if (stale.length === 0) console.log(" All skills up-to-date");
|
|
496
|
-
else for (const skill of stale) console.log(` ⚠ ${skill.name}: ${skill.reasons.join(", ")}`);
|
|
497
|
-
console.log();
|
|
498
|
-
}
|
|
499
|
-
return 0;
|
|
500
|
-
}
|
|
501
|
-
case "edit-package-json": {
|
|
502
|
-
const { runEditPackageJsonAll } = await import("./setup.mjs");
|
|
503
|
-
runEditPackageJsonAll(process.cwd());
|
|
504
|
-
return 0;
|
|
505
|
-
}
|
|
506
|
-
case "setup-github-actions": {
|
|
507
|
-
const { runSetupGithubActions } = await import("./setup.mjs");
|
|
508
|
-
runSetupGithubActions(process.cwd(), getMetaDir());
|
|
509
|
-
return 0;
|
|
510
|
-
}
|
|
511
|
-
default:
|
|
512
|
-
printHelp();
|
|
513
|
-
return command ? 1 : 0;
|
|
470
|
+
cli.parse([
|
|
471
|
+
"intent",
|
|
472
|
+
"intent",
|
|
473
|
+
...argv
|
|
474
|
+
], { run: false });
|
|
475
|
+
if (cli.options.help) return 0;
|
|
476
|
+
if (!cli.matchedCommand) {
|
|
477
|
+
cli.outputHelp();
|
|
478
|
+
return 1;
|
|
514
479
|
}
|
|
480
|
+
await cli.runMatchedCommand();
|
|
481
|
+
return 0;
|
|
515
482
|
} catch (err) {
|
|
516
483
|
if (isCliFailure(err)) {
|
|
517
484
|
console.error(err.message);
|
|
518
485
|
return err.exitCode;
|
|
519
486
|
}
|
|
487
|
+
if (err instanceof Error) {
|
|
488
|
+
console.error(err.message);
|
|
489
|
+
return 1;
|
|
490
|
+
}
|
|
520
491
|
throw err;
|
|
521
492
|
}
|
|
522
493
|
}
|
|
@@ -530,4 +501,4 @@ if (isMain) {
|
|
|
530
501
|
}
|
|
531
502
|
|
|
532
503
|
//#endregion
|
|
533
|
-
export {
|
|
504
|
+
export { main };
|