@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.mjs CHANGED
@@ -1,35 +1,75 @@
1
1
  #!/usr/bin/env node
2
- import { t as INSTALL_PROMPT } from "./install-prompt-C0M-U3WZ.mjs";
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
- function getMetaDir() {
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" && "message" in value && typeof value.message === "string" && "exitCode" in value && typeof value.exitCode === "number";
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-RWHFrJ_C.mjs");
35
+ const { scanForIntents } = await import("./scanner-CERQgrRN.mjs");
22
36
  try {
23
- return await scanForIntents();
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 printWarnings(warnings) {
29
- if (warnings.length === 0) return;
30
- console.log("Warnings:");
31
- for (const warning of warnings) console.log(` ⚠ ${warning}`);
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 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}`);
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, p) => sum + p.skills.length, 0);
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((p) => p.skills));
99
- const showTypes = result.packages.some((p) => p.skills.some((s) => s.type));
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(`Feedback:`);
110
- console.log(` Submit feedback on skill usage to help maintainers improve the skills.`);
111
- console.log(` Load: node_modules/@tanstack/intent/meta/feedback-collection/SKILL.md`);
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
- async function cmdMeta(args) {
116
- const { parseFrontmatter } = await import("./utils-D7OKi0Rn.mjs");
117
- const metaDir = getMetaDir();
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 (args.length > 0) {
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 entries = readdirSync(metaDir, { withFileTypes: true }).filter((e) => e.isDirectory()).filter((e) => existsSync(join(metaDir, e.name, "SKILL.md")));
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) + "..." : description;
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(`\nUsage: load the SKILL.md into your AI agent conversation.`);
145
- console.log(`Path: node_modules/@tanstack/intent/meta/<name>/SKILL.md`);
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
- function collectPackagingWarnings(root) {
148
- const pkgJsonPath = join(root, "package.json");
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 resolvePackageRoot(startDir) {
183
- let dir = startDir;
184
- while (true) {
185
- if (existsSync(join(dir, "package.json"))) return dir;
186
- const next = dirname(dir);
187
- if (next === dir) return startDir;
188
- dir = next;
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: "Invalid YAML frontmatter"
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: "Invalid YAML in artifact file"
411
+ message: `Invalid YAML in artifact file: ${detail}`
306
412
  });
307
413
  }
308
414
  }
309
- const warnings = collectPackagingWarnings(packageRoot);
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
- Check installed skills for version and source drift.
423
-
424
- Examples:
425
- intent stale
426
- intent stale packages/query
427
- intent stale --json`,
428
- "edit-package-json": `intent edit-package-json
429
-
430
- Update package.json files so skills are published.`,
431
- "setup-github-actions": `intent setup-github-actions
432
-
433
- Copy Intent CI workflow templates into .github/workflows/.`
434
- };
435
- function isHelpFlag(arg) {
436
- return arg === "-h" || arg === "--help";
437
- }
438
- function printHelp(command) {
439
- if (!command) {
440
- console.log(`${USAGE}
441
-
442
- Run \`intent help <command>\` for details on a specific command.`);
443
- return;
444
- }
445
- console.log(HELP_BY_COMMAND[command] ?? USAGE);
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
- if (!command || isHelpFlag(command)) {
452
- printHelp();
453
- return 0;
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
- if (isHelpFlag(commandArgs[0])) {
460
- printHelp(command);
461
- return 0;
462
- }
463
- switch (command) {
464
- case "list":
465
- await cmdList(commandArgs);
466
- return 0;
467
- case "meta":
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 { USAGE, main };
504
+ export { main };