@tanstack/intent 0.0.32 → 0.0.34

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.
Files changed (37) hide show
  1. package/README.md +7 -7
  2. package/dist/artifact-coverage-BAN2W6aH.mjs +3 -0
  3. package/dist/artifact-coverage-wLNVX8yC.mjs +128 -0
  4. package/dist/cli.mjs +248 -99
  5. package/dist/{display-DCRCp4-C.mjs → display-B3vkG99D.mjs} +1 -1
  6. package/dist/index.d.mts +22 -4
  7. package/dist/index.mjs +10 -8
  8. package/dist/{install-BmVqcbEi.mjs → install-QjryhQtg.mjs} +54 -18
  9. package/dist/intent-library.mjs +5 -5
  10. package/dist/library-scanner.d.mts +1 -1
  11. package/dist/library-scanner.mjs +1 -1
  12. package/dist/{project-context-CKG-q4rD.mjs → project-context-alYMNoNa.mjs} +1 -1
  13. package/dist/{resolver-aFigTqXi.mjs → resolver-Whd12ksO.mjs} +1 -1
  14. package/dist/scanner-BAZxWeUk.mjs +6 -0
  15. package/dist/{scanner-DKL8v8is.mjs → scanner-Dav1tzQK.mjs} +79 -4
  16. package/dist/{setup-JJvjiGkM.mjs → setup-Dp-W8y0Y.mjs} +2 -2
  17. package/dist/setup.d.mts +1 -1
  18. package/dist/setup.mjs +3 -3
  19. package/dist/staleness-DpbmYod4.mjs +5 -0
  20. package/dist/staleness-PdgakrCQ.mjs +243 -0
  21. package/dist/{types-CsySN6Vw.d.mts → types-DT7Y6TFz.d.mts} +48 -1
  22. package/dist/workflow-review-CwkPVIQf.mjs +153 -0
  23. package/dist/workflow-review-Dz_ofcYQ.mjs +3 -0
  24. package/dist/{workspace-patterns-U35B5AO-.mjs → workspace-patterns-BN2A_60g.mjs} +6 -1
  25. package/dist/workspace-patterns-x-dLZxx4.mjs +4 -0
  26. package/meta/templates/workflows/check-skills.yml +58 -96
  27. package/package.json +1 -1
  28. package/dist/scanner-CRZITpcY.mjs +0 -6
  29. package/dist/staleness-DorwfGrf.mjs +0 -104
  30. package/dist/staleness-NF-lxfXf.mjs +0 -4
  31. package/dist/workspace-patterns-DbnA0peB.mjs +0 -4
  32. package/meta/templates/workflows/notify-intent.yml +0 -51
  33. package/meta/templates/workflows/validate-skills.yml +0 -52
  34. /package/dist/{display-DUgtRJkt.mjs → display-CAof6doy.mjs} +0 -0
  35. /package/dist/{library-scanner-DFFreLjW.mjs → library-scanner-fexXlPXb.mjs} +0 -0
  36. /package/dist/{setup-DDoOLriA.d.mts → setup-t1i2o2-h.d.mts} +0 -0
  37. /package/dist/{skill-use-CXOnncWK.mjs → skill-use-BzuuvLM7.mjs} +0 -0
package/dist/index.mjs CHANGED
@@ -1,12 +1,14 @@
1
1
  import { a as parseFrontmatter, n as findSkillFiles, o as resolveDepDir, r as getDeps } from "./utils-COlDcU72.mjs";
2
2
  import "./skill-paths-8k9K9y26.mjs";
3
- import { t as scanForIntents } from "./scanner-DKL8v8is.mjs";
4
- import "./workspace-patterns-U35B5AO-.mjs";
5
- import { t as checkStaleness } from "./staleness-DorwfGrf.mjs";
6
- import { i as parseSkillUse, n as formatSkillUse, r as isSkillUseParseError, t as SkillUseParseError } from "./skill-use-CXOnncWK.mjs";
7
- import { n as isResolveSkillUseError, r as resolveSkillUse, t as ResolveSkillUseError } from "./resolver-aFigTqXi.mjs";
8
- import "./project-context-CKG-q4rD.mjs";
9
- import { r as runSetupGithubActions, t as runEditPackageJson } from "./setup-JJvjiGkM.mjs";
3
+ import { t as scanForIntents } from "./scanner-Dav1tzQK.mjs";
4
+ import "./workspace-patterns-BN2A_60g.mjs";
5
+ import { t as readIntentArtifacts } from "./artifact-coverage-wLNVX8yC.mjs";
6
+ import { n as checkStaleness } from "./staleness-PdgakrCQ.mjs";
7
+ import { n as collectStaleReviewItems, r as createFailedStaleReviewItem, t as buildStaleReviewBody } from "./workflow-review-CwkPVIQf.mjs";
8
+ import { i as parseSkillUse, n as formatSkillUse, r as isSkillUseParseError, t as SkillUseParseError } from "./skill-use-BzuuvLM7.mjs";
9
+ import { n as isResolveSkillUseError, r as resolveSkillUse, t as ResolveSkillUseError } from "./resolver-Whd12ksO.mjs";
10
+ import "./project-context-alYMNoNa.mjs";
11
+ import { r as runSetupGithubActions, t as runEditPackageJson } from "./setup-Dp-W8y0Y.mjs";
10
12
  import { readFileSync, writeFileSync } from "node:fs";
11
13
  import { join } from "node:path";
12
14
  import { execFileSync, execSync } from "node:child_process";
@@ -274,4 +276,4 @@ function submitMetaFeedback(payload, opts) {
274
276
  }
275
277
 
276
278
  //#endregion
277
- export { ResolveSkillUseError, SkillUseParseError, checkStaleness, containsSecrets, findSkillFiles, formatSkillUse, getDeps, hasGhCli, isResolveSkillUseError, isSkillUseParseError, metaToMarkdown, parseFrontmatter, parseSkillUse, resolveDepDir, resolveFrequency, resolveSkillUse, runEditPackageJson, runSetupGithubActions, scanForIntents, submitFeedback, submitMetaFeedback, toMarkdown, validateMetaPayload, validatePayload };
279
+ export { ResolveSkillUseError, SkillUseParseError, buildStaleReviewBody, checkStaleness, collectStaleReviewItems, containsSecrets, createFailedStaleReviewItem, findSkillFiles, formatSkillUse, getDeps, hasGhCli, isResolveSkillUseError, isSkillUseParseError, metaToMarkdown, parseFrontmatter, parseSkillUse, readIntentArtifacts, resolveDepDir, resolveFrequency, resolveSkillUse, runEditPackageJson, runSetupGithubActions, scanForIntents, submitFeedback, submitMetaFeedback, toMarkdown, validateMetaPayload, validatePayload };
@@ -1,5 +1,5 @@
1
- import { i as parseSkillUse, n as formatSkillUse } from "./skill-use-CXOnncWK.mjs";
2
- import { t as resolveProjectContext } from "./project-context-CKG-q4rD.mjs";
1
+ import { i as parseSkillUse, n as formatSkillUse } from "./skill-use-BzuuvLM7.mjs";
2
+ import { t as resolveProjectContext } from "./project-context-alYMNoNa.mjs";
3
3
  import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
4
4
  import { dirname, join, relative, resolve } from "node:path";
5
5
  import { parse } from "yaml";
@@ -28,11 +28,25 @@ function printWarnings(warnings) {
28
28
 
29
29
  //#endregion
30
30
  //#region src/cli-support.ts
31
+ const INTENT_CHECK_SKILLS_WORKFLOW_VERSION = 3;
31
32
  function getMetaDir() {
32
33
  return join(dirname(fileURLToPath(import.meta.url)), "..", "meta");
33
34
  }
35
+ function getCheckSkillsWorkflowAdvisories(root) {
36
+ const workflowPath = join(root, ".github", "workflows", "check-skills.yml");
37
+ if (!existsSync(workflowPath)) return [];
38
+ let content;
39
+ try {
40
+ content = readFileSync(workflowPath, "utf8");
41
+ } catch {
42
+ return [];
43
+ }
44
+ const versionMatch = content.match(/intent-workflow-version:\s*(\d+)/);
45
+ if ((versionMatch ? Number(versionMatch[1]) : 0) >= INTENT_CHECK_SKILLS_WORKFLOW_VERSION) return [];
46
+ return [`Intent workflow update available: run \`npx @tanstack/intent@latest setup\` to refresh ${relative(process.cwd(), workflowPath) || workflowPath}.`];
47
+ }
34
48
  async function scanIntentsOrFail(options) {
35
- const { scanForIntents } = await import("./scanner-CRZITpcY.mjs");
49
+ const { scanForIntents } = await import("./scanner-BAZxWeUk.mjs");
36
50
  try {
37
51
  return scanForIntents(void 0, options);
38
52
  } catch (err) {
@@ -45,31 +59,53 @@ function scanOptionsFromGlobalFlags(options) {
45
59
  if (options.global) return { scope: "local-and-global" };
46
60
  return { scope: "local" };
47
61
  }
48
- function readPackageName(root) {
49
- try {
50
- const pkgJson = JSON.parse(readFileSync(join(root, "package.json"), "utf8"));
51
- return typeof pkgJson.name === "string" ? pkgJson.name : relative(process.cwd(), root) || "unknown";
52
- } catch {
53
- return relative(process.cwd(), root) || "unknown";
54
- }
55
- }
56
62
  async function resolveStaleTargets(targetDir) {
57
63
  const resolvedRoot = targetDir ? resolve(process.cwd(), targetDir) : process.cwd();
58
64
  const context = resolveProjectContext({
59
65
  cwd: process.cwd(),
60
66
  targetPath: targetDir
61
67
  });
62
- const { checkStaleness } = await import("./staleness-NF-lxfXf.mjs");
63
- if (context.packageRoot && (context.targetSkillsDir !== null || resolvedRoot !== context.workspaceRoot)) return { reports: [await checkStaleness(context.packageRoot, readPackageName(context.packageRoot))] };
64
- if (existsSync(join(resolvedRoot, "skills"))) return { reports: [await checkStaleness(resolvedRoot, readPackageName(resolvedRoot))] };
65
- const { findPackagesWithSkills, findWorkspaceRoot } = await import("./workspace-patterns-DbnA0peB.mjs");
68
+ const workflowAdvisories = getCheckSkillsWorkflowAdvisories(context.workspaceRoot ?? context.packageRoot ?? resolvedRoot);
69
+ const { buildWorkspaceCoverageSignals, checkStaleness, readPackageName } = await import("./staleness-DpbmYod4.mjs");
70
+ const isWorkspaceRootTarget = context.workspaceRoot !== null && resolvedRoot === context.workspaceRoot;
71
+ if (context.packageRoot && !isWorkspaceRootTarget && (context.targetSkillsDir !== null || context.workspaceRoot === null)) return {
72
+ reports: [await checkStaleness(context.packageRoot, readPackageName(context.packageRoot), context.workspaceRoot ?? context.packageRoot)],
73
+ workflowAdvisories
74
+ };
75
+ const { findPackagesWithSkills, findWorkspacePackages, findWorkspaceRoot } = await import("./workspace-patterns-x-dLZxx4.mjs");
66
76
  const workspaceRoot = findWorkspaceRoot(resolvedRoot);
67
77
  if (workspaceRoot) {
68
- const packageDirs = findPackagesWithSkills(workspaceRoot);
69
- if (packageDirs.length > 0) return { reports: await Promise.all(packageDirs.map((packageDir) => checkStaleness(packageDir, readPackageName(packageDir)))) };
78
+ const packageDirsWithSkills = findPackagesWithSkills(workspaceRoot);
79
+ const allPackageDirs = findWorkspacePackages(workspaceRoot);
80
+ const reports = await Promise.all(packageDirsWithSkills.map((packageDir) => checkStaleness(packageDir, readPackageName(packageDir), workspaceRoot)));
81
+ const { readIntentArtifacts } = await import("./artifact-coverage-BAN2W6aH.mjs");
82
+ const coverageSignals = buildWorkspaceCoverageSignals({
83
+ artifactRoot: workspaceRoot,
84
+ artifacts: existsSync(join(workspaceRoot, "_artifacts")) ? readIntentArtifacts(workspaceRoot) : null,
85
+ packageDirs: allPackageDirs
86
+ });
87
+ if (coverageSignals.length > 0) reports.push({
88
+ library: relative(process.cwd(), workspaceRoot) || "workspace",
89
+ currentVersion: null,
90
+ skillVersion: null,
91
+ versionDrift: null,
92
+ skills: [],
93
+ signals: coverageSignals
94
+ });
95
+ if (reports.length > 0) return {
96
+ reports,
97
+ workflowAdvisories
98
+ };
70
99
  }
100
+ if (existsSync(join(resolvedRoot, "skills"))) return {
101
+ reports: [await checkStaleness(resolvedRoot, readPackageName(resolvedRoot))],
102
+ workflowAdvisories
103
+ };
71
104
  const staleResult = await scanIntentsOrFail();
72
- return { reports: await Promise.all(staleResult.packages.map((pkg) => checkStaleness(pkg.packageRoot, pkg.name))) };
105
+ return {
106
+ reports: await Promise.all(staleResult.packages.map((pkg) => checkStaleness(pkg.packageRoot, pkg.name))),
107
+ workflowAdvisories
108
+ };
73
109
  }
74
110
 
75
111
  //#endregion
@@ -1,11 +1,11 @@
1
1
  #!/usr/bin/env node
2
2
  import "./utils-COlDcU72.mjs";
3
3
  import "./skill-paths-8k9K9y26.mjs";
4
- import "./workspace-patterns-U35B5AO-.mjs";
5
- import "./project-context-CKG-q4rD.mjs";
6
- import { t as INSTALL_PROMPT } from "./install-BmVqcbEi.mjs";
7
- import { n as printSkillTree, r as printTable, t as computeSkillNameWidth } from "./display-DUgtRJkt.mjs";
8
- import { t as scanLibrary } from "./library-scanner-DFFreLjW.mjs";
4
+ import "./workspace-patterns-BN2A_60g.mjs";
5
+ import "./project-context-alYMNoNa.mjs";
6
+ import { t as INSTALL_PROMPT } from "./install-QjryhQtg.mjs";
7
+ import { n as printSkillTree, r as printTable, t as computeSkillNameWidth } from "./display-CAof6doy.mjs";
8
+ import { t as scanLibrary } from "./library-scanner-fexXlPXb.mjs";
9
9
 
10
10
  //#region src/intent-library.ts
11
11
  function cmdList() {
@@ -1,4 +1,4 @@
1
- import { u as SkillEntry } from "./types-CsySN6Vw.mjs";
1
+ import { h as SkillEntry } from "./types-DT7Y6TFz.mjs";
2
2
 
3
3
  //#region src/library-scanner.d.ts
4
4
  interface LibraryPackage {
@@ -1,5 +1,5 @@
1
1
  import "./utils-COlDcU72.mjs";
2
2
  import "./skill-paths-8k9K9y26.mjs";
3
- import { t as scanLibrary } from "./library-scanner-DFFreLjW.mjs";
3
+ import { t as scanLibrary } from "./library-scanner-fexXlPXb.mjs";
4
4
 
5
5
  export { scanLibrary };
@@ -1,4 +1,4 @@
1
- import { n as findWorkspaceRoot, r as readWorkspacePatterns } from "./workspace-patterns-U35B5AO-.mjs";
1
+ import { i as readWorkspacePatterns, r as findWorkspaceRoot } from "./workspace-patterns-BN2A_60g.mjs";
2
2
  import { existsSync, statSync } from "node:fs";
3
3
  import { dirname, join, relative, resolve } from "node:path";
4
4
 
@@ -1,4 +1,4 @@
1
- import { i as parseSkillUse } from "./skill-use-CXOnncWK.mjs";
1
+ import { i as parseSkillUse } from "./skill-use-BzuuvLM7.mjs";
2
2
 
3
3
  //#region src/resolver.ts
4
4
  var ResolveSkillUseError = class extends Error {
@@ -0,0 +1,6 @@
1
+ import "./utils-COlDcU72.mjs";
2
+ import "./skill-paths-8k9K9y26.mjs";
3
+ import { t as scanForIntents } from "./scanner-Dav1tzQK.mjs";
4
+ import "./workspace-patterns-BN2A_60g.mjs";
5
+
6
+ export { scanForIntents };
@@ -1,8 +1,9 @@
1
1
  import { a as parseFrontmatter, i as listNodeModulesPackageDirs, o as resolveDepDir, r as getDeps, s as toPosixPath, t as detectGlobalNodeModules } from "./utils-COlDcU72.mjs";
2
2
  import { r as rewriteSkillLoadPaths } from "./skill-paths-8k9K9y26.mjs";
3
- import { i as resolveWorkspacePackages, n as findWorkspaceRoot, r as readWorkspacePatterns } from "./workspace-patterns-U35B5AO-.mjs";
3
+ import { a as resolveWorkspacePackages, i as readWorkspacePatterns, r as findWorkspaceRoot } from "./workspace-patterns-BN2A_60g.mjs";
4
+ import { createRequire } from "node:module";
4
5
  import { existsSync, readFileSync, readdirSync } from "node:fs";
5
- import { join, relative, sep } from "node:path";
6
+ import { dirname, join, relative, resolve, sep } from "node:path";
6
7
 
7
8
  //#region src/discovery/register.ts
8
9
  function isLocalToProject(dirPath, projectRoot) {
@@ -132,13 +133,31 @@ function createDependencyWalker(opts) {
132
133
 
133
134
  //#endregion
134
135
  //#region src/scanner.ts
135
- function detectPackageManager(root) {
136
- if (existsSync(join(root, ".pnp.cjs")) || existsSync(join(root, ".pnp.js"))) throw new Error("Yarn PnP is not yet supported. Add `nodeLinker: node-modules` to your .yarnrc.yml to use intent.");
136
+ const requireFromHere = createRequire(import.meta.url);
137
+ function findPnpFile(start) {
138
+ let dir = resolve(start);
139
+ while (true) {
140
+ for (const fileName of [".pnp.cjs", ".pnp.js"]) {
141
+ const pnpPath = join(dir, fileName);
142
+ if (existsSync(pnpPath)) return pnpPath;
143
+ }
144
+ const next = dirname(dir);
145
+ if (next === dir) return null;
146
+ dir = next;
147
+ }
148
+ }
149
+ function isYarnPnpProject(root) {
150
+ return findPnpFile(root) !== null;
151
+ }
152
+ function assertLocalNodeModulesSupported(root) {
137
153
  if (existsSync(join(root, "deno.json")) && !existsSync(join(root, "node_modules"))) throw new Error("Deno without node_modules is not yet supported. Add `\"nodeModulesDir\": \"auto\"` to your deno.json to use intent.");
154
+ }
155
+ function detectPackageManager(root) {
138
156
  const dirsToCheck = [root];
139
157
  const wsRoot = findWorkspaceRoot(root);
140
158
  if (wsRoot && wsRoot !== root) dirsToCheck.push(wsRoot);
141
159
  for (const dir of dirsToCheck) {
160
+ if (isYarnPnpProject(dir)) return "yarn";
142
161
  if (existsSync(join(dir, "pnpm-lock.yaml"))) return "pnpm";
143
162
  if (existsSync(join(dir, "bun.lockb")) || existsSync(join(dir, "bun.lock"))) return "bun";
144
163
  if (existsSync(join(dir, "yarn.lock"))) return "yarn";
@@ -146,6 +165,35 @@ function detectPackageManager(root) {
146
165
  }
147
166
  return "unknown";
148
167
  }
168
+ function loadPnpApi(root) {
169
+ const pnpPath = findPnpFile(root);
170
+ if (!pnpPath) return null;
171
+ try {
172
+ const foundApi = requireFromHere("node:module").findPnpApi?.(root);
173
+ if (foundApi) return foundApi;
174
+ const pnpModule = requireFromHere(pnpPath);
175
+ if (typeof pnpModule.setup === "function") pnpModule.setup();
176
+ if (typeof pnpModule.getDependencyTreeRoots === "function" && typeof pnpModule.getPackageInformation === "function") return pnpModule;
177
+ return createRequire(join(dirname(pnpPath), "package.json"))("pnpapi");
178
+ } catch (err) {
179
+ const msg = err instanceof Error ? err.message : String(err);
180
+ throw new Error(`Yarn PnP project detected, but Intent could not load Yarn's PnP API from ${pnpPath}: ${msg}`);
181
+ }
182
+ }
183
+ function getPnpLocatorKey(locator) {
184
+ return `${locator.name ?? "<top>"}@${locator.reference ?? "<top>"}`;
185
+ }
186
+ function getPnpDependencyLocator(dependencyName, target) {
187
+ if (target === null) return null;
188
+ if (Array.isArray(target)) return {
189
+ name: target[0],
190
+ reference: target[1]
191
+ };
192
+ return {
193
+ name: dependencyName,
194
+ reference: target
195
+ };
196
+ }
149
197
  function validateIntentField(_pkgName, intent) {
150
198
  if (!intent || typeof intent !== "object") return null;
151
199
  const pb = intent;
@@ -304,6 +352,7 @@ function scanForIntents(root, options = {}) {
304
352
  const projectRoot = root ?? process.cwd();
305
353
  const scanScope = getScanScope(options);
306
354
  const packageManager = detectPackageManager(projectRoot);
355
+ const pnpApi = scanScope === "global" ? null : loadPnpApi(projectRoot);
307
356
  const nodeModulesDir = join(projectRoot, "node_modules");
308
357
  const explicitGlobalNodeModules = process.env.INTENT_GLOBAL_NODE_MODULES?.trim() || null;
309
358
  const packages = [];
@@ -378,7 +427,33 @@ function scanForIntents(root, options = {}) {
378
427
  tryRegister,
379
428
  warnings
380
429
  });
430
+ function scanPnpPackages() {
431
+ if (!pnpApi) return;
432
+ const api = pnpApi;
433
+ const visited = /* @__PURE__ */ new Set();
434
+ const workspaceRoot = findWorkspaceRoot(projectRoot);
435
+ const projectLocator = api.findPackageLocator?.(projectRoot.endsWith(sep) ? projectRoot : `${projectRoot}${sep}`);
436
+ const roots = workspaceRoot && workspaceRoot !== projectRoot && projectLocator ? [projectLocator] : api.getDependencyTreeRoots?.() ?? (api.topLevel ? [api.topLevel] : []);
437
+ function visit(locator) {
438
+ const key = getPnpLocatorKey(locator);
439
+ if (visited.has(key)) return;
440
+ visited.add(key);
441
+ const info = api.getPackageInformation(locator);
442
+ if (!info) return;
443
+ tryRegister(info.packageLocation.replace(/[\\/]$/, ""), locator.name ?? "unknown");
444
+ for (const [dependencyName, target] of info.packageDependencies) {
445
+ const dependencyLocator = getPnpDependencyLocator(dependencyName, target);
446
+ if (dependencyLocator) visit(dependencyLocator);
447
+ }
448
+ }
449
+ for (const locator of roots) visit(locator);
450
+ }
381
451
  function scanLocalPackages() {
452
+ if (pnpApi && !nodeModules.local.exists) {
453
+ scanPnpPackages();
454
+ return;
455
+ }
456
+ assertLocalNodeModulesSupported(projectRoot);
382
457
  scanTarget(nodeModules.local);
383
458
  walkWorkspacePackages();
384
459
  walkKnownPackages();
@@ -1,5 +1,5 @@
1
- import { n as findWorkspaceRoot, r as readWorkspacePatterns, t as findPackagesWithSkills } from "./workspace-patterns-U35B5AO-.mjs";
2
- import { t as resolveProjectContext } from "./project-context-CKG-q4rD.mjs";
1
+ import { i as readWorkspacePatterns, r as findWorkspaceRoot, t as findPackagesWithSkills } from "./workspace-patterns-BN2A_60g.mjs";
2
+ import { t as resolveProjectContext } from "./project-context-alYMNoNa.mjs";
3
3
  import { existsSync, mkdirSync, readFileSync, readdirSync, writeFileSync } from "node:fs";
4
4
  import { basename, join, relative } from "node:path";
5
5
 
package/dist/setup.d.mts CHANGED
@@ -1,2 +1,2 @@
1
- import { a as runEditPackageJsonAll, c as findWorkspaceRoot, i as runEditPackageJson, l as readWorkspacePatterns, n as MonorepoResult, o as runSetupGithubActions, r as SetupGithubActionsResult, s as findPackagesWithSkills, t as EditPackageJsonResult, u as resolveWorkspacePackages } from "./setup-DDoOLriA.mjs";
1
+ import { a as runEditPackageJsonAll, c as findWorkspaceRoot, i as runEditPackageJson, l as readWorkspacePatterns, n as MonorepoResult, o as runSetupGithubActions, r as SetupGithubActionsResult, s as findPackagesWithSkills, t as EditPackageJsonResult, u as resolveWorkspacePackages } from "./setup-t1i2o2-h.mjs";
2
2
  export { EditPackageJsonResult, MonorepoResult, SetupGithubActionsResult, findPackagesWithSkills, findWorkspaceRoot, readWorkspacePatterns, resolveWorkspacePackages, runEditPackageJson, runEditPackageJsonAll, runSetupGithubActions };
package/dist/setup.mjs CHANGED
@@ -1,6 +1,6 @@
1
1
  import "./utils-COlDcU72.mjs";
2
- import { i as resolveWorkspacePackages, n as findWorkspaceRoot, r as readWorkspacePatterns, t as findPackagesWithSkills } from "./workspace-patterns-U35B5AO-.mjs";
3
- import "./project-context-CKG-q4rD.mjs";
4
- import { n as runEditPackageJsonAll, r as runSetupGithubActions, t as runEditPackageJson } from "./setup-JJvjiGkM.mjs";
2
+ import { a as resolveWorkspacePackages, i as readWorkspacePatterns, r as findWorkspaceRoot, t as findPackagesWithSkills } from "./workspace-patterns-BN2A_60g.mjs";
3
+ import "./project-context-alYMNoNa.mjs";
4
+ import { n as runEditPackageJsonAll, r as runSetupGithubActions, t as runEditPackageJson } from "./setup-Dp-W8y0Y.mjs";
5
5
 
6
6
  export { findPackagesWithSkills, findWorkspaceRoot, readWorkspacePatterns, resolveWorkspacePackages, runEditPackageJson, runEditPackageJsonAll, runSetupGithubActions };
@@ -0,0 +1,5 @@
1
+ import "./utils-COlDcU72.mjs";
2
+ import "./artifact-coverage-wLNVX8yC.mjs";
3
+ import { n as checkStaleness, r as readPackageName, t as buildWorkspaceCoverageSignals } from "./staleness-PdgakrCQ.mjs";
4
+
5
+ export { buildWorkspaceCoverageSignals, checkStaleness, readPackageName };
@@ -0,0 +1,243 @@
1
+ import { a as parseFrontmatter, n as findSkillFiles } from "./utils-COlDcU72.mjs";
2
+ import { t as readIntentArtifacts } from "./artifact-coverage-wLNVX8yC.mjs";
3
+ import { existsSync, readFileSync } from "node:fs";
4
+ import { isAbsolute, join, relative, resolve, sep } from "node:path";
5
+
6
+ //#region src/staleness.ts
7
+ function classifyVersionDrift(oldVer, newVer) {
8
+ if (oldVer === newVer) return null;
9
+ const oldParts = oldVer.replace(/[^0-9.]/g, "").split(".").map(Number);
10
+ const newParts = newVer.replace(/[^0-9.]/g, "").split(".").map(Number);
11
+ if ((newParts[0] ?? 0) > (oldParts[0] ?? 0)) return "major";
12
+ if ((newParts[1] ?? 0) > (oldParts[1] ?? 0)) return "minor";
13
+ if ((newParts[2] ?? 0) > (oldParts[2] ?? 0)) return "patch";
14
+ return null;
15
+ }
16
+ function readLocalVersion(packageDir) {
17
+ try {
18
+ const pkgJson = JSON.parse(readFileSync(join(packageDir, "package.json"), "utf8"));
19
+ return typeof pkgJson.version === "string" ? pkgJson.version : null;
20
+ } catch {
21
+ return null;
22
+ }
23
+ }
24
+ async function fetchNpmVersion(packageName) {
25
+ try {
26
+ const res = await fetch(`https://registry.npmjs.org/${encodeURIComponent(packageName)}/latest`);
27
+ if (!res.ok) return null;
28
+ const data = await res.json();
29
+ return typeof data.version === "string" ? data.version : null;
30
+ } catch {
31
+ return null;
32
+ }
33
+ }
34
+ async function fetchCurrentVersion(packageDir, packageName) {
35
+ return readLocalVersion(packageDir) ?? await fetchNpmVersion(packageName);
36
+ }
37
+ function isStringRecord(value) {
38
+ return !!value && typeof value === "object" && !Array.isArray(value) && Object.values(value).every((entry) => typeof entry === "string");
39
+ }
40
+ function parseSyncState(value) {
41
+ if (!value || typeof value !== "object") return null;
42
+ const raw = value;
43
+ const parsed = {};
44
+ if (typeof raw.library_version === "string") parsed.library_version = raw.library_version;
45
+ if (raw.skills && typeof raw.skills === "object") {
46
+ const skills = {};
47
+ for (const [skillName, skillValue] of Object.entries(raw.skills)) {
48
+ if (!skillValue || typeof skillValue !== "object") continue;
49
+ const sourcesSha = skillValue.sources_sha;
50
+ if (sourcesSha !== void 0 && !isStringRecord(sourcesSha)) continue;
51
+ skills[skillName] = {};
52
+ if (sourcesSha) skills[skillName].sources_sha = sourcesSha;
53
+ }
54
+ parsed.skills = skills;
55
+ }
56
+ return parsed;
57
+ }
58
+ function readSyncState(packageDir) {
59
+ const statePath = join(packageDir, "skills", "sync-state.json");
60
+ try {
61
+ return parseSyncState(JSON.parse(readFileSync(statePath, "utf8")));
62
+ } catch {
63
+ return null;
64
+ }
65
+ }
66
+ function readPackageName(packageDir) {
67
+ const packageJson = readPackageJson(packageDir);
68
+ return typeof packageJson?.name === "string" ? packageJson.name : relative(process.cwd(), packageDir) || "unknown";
69
+ }
70
+ function readPackageJson(packageDir) {
71
+ try {
72
+ return JSON.parse(readFileSync(join(packageDir, "package.json"), "utf8"));
73
+ } catch {
74
+ return null;
75
+ }
76
+ }
77
+ function normalizeFilePath(path) {
78
+ return resolve(path).split(sep).join("/");
79
+ }
80
+ function normalizeList(values) {
81
+ return [...new Set(values ?? [])].sort((a, b) => a.localeCompare(b));
82
+ }
83
+ function sameStringList(a, b) {
84
+ const left = normalizeList(a);
85
+ const right = normalizeList(b);
86
+ return left.length === right.length && left.every((value, index) => value === right[index]);
87
+ }
88
+ function artifactPackageMatches(artifact, packageDir, packageName, artifactRoot) {
89
+ const relPackageDir = relative(artifactRoot, packageDir).split(sep).join("/");
90
+ if (!relPackageDir) return true;
91
+ if (artifact.packages.includes(packageName)) return true;
92
+ if (artifact.packages.includes(relPackageDir)) return true;
93
+ if (artifact.path?.startsWith(`${relPackageDir}/`)) return true;
94
+ return artifact.packages.length === 0 && artifact.path === void 0;
95
+ }
96
+ function resolveArtifactSkillPaths(artifact, packageDir, artifactRoot) {
97
+ if (!artifact.path) return [];
98
+ const candidatePaths = [isAbsolute(artifact.path) ? artifact.path : join(artifactRoot, artifact.path), isAbsolute(artifact.path) ? artifact.path : join(packageDir, artifact.path)];
99
+ if (artifact.package && artifact.path.startsWith("skills/")) candidatePaths.push(join(artifactRoot, artifact.package, artifact.path));
100
+ return [...new Set(candidatePaths.map(normalizeFilePath))];
101
+ }
102
+ function findMatchingSkill(artifact, skillMetas, packageDir, artifactRoot) {
103
+ const skillsByPath = new Map(skillMetas.map((skill) => [normalizeFilePath(skill.filePath), skill]));
104
+ for (const candidatePath of resolveArtifactSkillPaths(artifact, packageDir, artifactRoot)) {
105
+ const match = skillsByPath.get(candidatePath);
106
+ if (match) return match;
107
+ }
108
+ const skillsByName = /* @__PURE__ */ new Map();
109
+ for (const skill of skillMetas) {
110
+ skillsByName.set(skill.name, skill);
111
+ skillsByName.set(skill.relName, skill);
112
+ }
113
+ return (artifact.slug ? skillsByName.get(artifact.slug) : void 0) ?? (artifact.name ? skillsByName.get(artifact.name) : void 0) ?? null;
114
+ }
115
+ function buildArtifactSignals({ artifactRoot, artifacts, library, packageDir, skillMetas }) {
116
+ if (!artifacts) return [];
117
+ const artifactFiles = new Map([...artifacts.skillTrees, ...artifacts.domainMaps].map((file) => [file.path, file]));
118
+ const signals = artifacts.warnings.map((warning) => ({
119
+ type: "artifact-parse-warning",
120
+ library,
121
+ subject: warning.artifactPath,
122
+ reasons: [warning.message],
123
+ needsReview: true,
124
+ artifactPath: warning.artifactPath
125
+ }));
126
+ for (const artifact of artifacts.skills) {
127
+ if (!artifactPackageMatches(artifact, packageDir, library, artifactRoot)) continue;
128
+ const subject = artifact.slug ?? artifact.name ?? artifact.path;
129
+ const matchingSkill = findMatchingSkill(artifact, skillMetas, packageDir, artifactRoot);
130
+ if (artifact.path && !matchingSkill) {
131
+ signals.push({
132
+ type: "artifact-skill-missing",
133
+ library,
134
+ subject,
135
+ reasons: [`artifact skill path does not resolve to a generated SKILL.md (${artifact.path})`],
136
+ needsReview: true,
137
+ artifactPath: artifact.artifactPath,
138
+ skill: artifact.slug ?? artifact.name
139
+ });
140
+ continue;
141
+ }
142
+ if (!matchingSkill) continue;
143
+ if (matchingSkill.sources !== void 0 && artifact.sources.length > 0 && !sameStringList(matchingSkill.sources, artifact.sources)) signals.push({
144
+ type: "artifact-source-drift",
145
+ library,
146
+ subject,
147
+ reasons: ["artifact sources differ from SKILL.md frontmatter sources"],
148
+ needsReview: true,
149
+ artifactPath: artifact.artifactPath,
150
+ skill: matchingSkill.name
151
+ });
152
+ const artifactVersion = artifactFiles.get(artifact.artifactPath)?.libraryVersion;
153
+ if (artifactVersion && matchingSkill.libraryVersion && artifactVersion !== matchingSkill.libraryVersion) signals.push({
154
+ type: "artifact-library-version-drift",
155
+ library,
156
+ subject,
157
+ reasons: [`artifact library.version (${artifactVersion}) differs from SKILL.md library_version (${matchingSkill.libraryVersion})`],
158
+ needsReview: true,
159
+ artifactPath: artifact.artifactPath,
160
+ skill: matchingSkill.name
161
+ });
162
+ }
163
+ return signals;
164
+ }
165
+ function artifactCoversPackage(artifact, packageDir, packageName, artifactRoot) {
166
+ const relPackageDir = relative(artifactRoot, packageDir).split(sep).join("/");
167
+ return artifact.packages.includes(packageName) || artifact.packages.includes(relPackageDir) || artifact.package === packageName || artifact.package === relPackageDir || artifact.path?.startsWith(`${relPackageDir}/`) === true;
168
+ }
169
+ function artifactIgnoresPackage(artifacts, packageDir, packageName, artifactRoot) {
170
+ const relPackageDir = relative(artifactRoot, packageDir).split(sep).join("/");
171
+ return artifacts.ignoredPackages.some((ignored) => ignored.packageName === packageName || ignored.packageName === relPackageDir);
172
+ }
173
+ function buildWorkspaceCoverageSignals({ artifactRoot, artifacts, packageDirs }) {
174
+ if (!artifacts) return [];
175
+ const signals = [];
176
+ for (const packageDir of packageDirs) {
177
+ if (readPackageJson(packageDir)?.private === true) continue;
178
+ const packageName = readPackageName(packageDir);
179
+ if (artifactIgnoresPackage(artifacts, packageDir, packageName, artifactRoot)) continue;
180
+ const hasGeneratedSkill = findSkillFiles(join(packageDir, "skills")).length > 0;
181
+ const hasArtifactCoverage = artifacts.skills.some((artifact) => artifactCoversPackage(artifact, packageDir, packageName, artifactRoot));
182
+ if (hasGeneratedSkill || hasArtifactCoverage) continue;
183
+ signals.push({
184
+ type: "missing-package-coverage",
185
+ library: packageName,
186
+ subject: packageName,
187
+ reasons: ["workspace package is not represented by generated skills or _artifacts coverage"],
188
+ needsReview: true,
189
+ packageName,
190
+ packageRoot: relative(artifactRoot, packageDir).split(sep).join("/")
191
+ });
192
+ }
193
+ return signals;
194
+ }
195
+ async function checkStaleness(packageDir, packageName, artifactRoot = packageDir) {
196
+ const skillsDir = join(packageDir, "skills");
197
+ const library = packageName ?? "unknown";
198
+ const skillMetas = findSkillFiles(skillsDir).map((filePath) => {
199
+ const fm = parseFrontmatter(filePath);
200
+ const relName = relative(skillsDir, filePath).replace(/[/\\]SKILL\.md$/, "").split(sep).join("/");
201
+ return {
202
+ name: typeof fm?.name === "string" ? fm.name : relName,
203
+ relName,
204
+ filePath,
205
+ libraryVersion: fm?.library_version,
206
+ sources: Array.isArray(fm?.sources) ? fm.sources : void 0
207
+ };
208
+ });
209
+ const artifacts = existsSync(join(artifactRoot, "_artifacts")) ? readIntentArtifacts(artifactRoot) : null;
210
+ const skillVersion = skillMetas.find((s) => s.libraryVersion)?.libraryVersion ?? null;
211
+ const currentVersion = await fetchCurrentVersion(packageDir, library);
212
+ const versionDrift = skillVersion && currentVersion ? classifyVersionDrift(skillVersion, currentVersion) : null;
213
+ const syncState = readSyncState(packageDir);
214
+ return {
215
+ library,
216
+ currentVersion,
217
+ skillVersion,
218
+ versionDrift,
219
+ skills: skillMetas.map((skill) => {
220
+ const reasons = [];
221
+ if (currentVersion && skill.libraryVersion && skill.libraryVersion !== currentVersion) reasons.push(`version drift (${skill.libraryVersion} → ${currentVersion})`);
222
+ const storedShas = syncState?.skills?.[skill.name]?.sources_sha ?? {};
223
+ if (skill.sources && Object.keys(storedShas).length > 0) {
224
+ for (const source of skill.sources) if (!storedShas[source]) reasons.push(`new source (${source})`);
225
+ }
226
+ return {
227
+ name: skill.name,
228
+ reasons,
229
+ needsReview: reasons.length > 0
230
+ };
231
+ }),
232
+ signals: buildArtifactSignals({
233
+ artifactRoot,
234
+ artifacts,
235
+ library,
236
+ packageDir,
237
+ skillMetas
238
+ })
239
+ };
240
+ }
241
+
242
+ //#endregion
243
+ export { checkStaleness as n, readPackageName as r, buildWorkspaceCoverageSignals as t };
@@ -57,12 +57,59 @@ interface StalenessReport {
57
57
  skillVersion: string | null;
58
58
  versionDrift: 'major' | 'minor' | 'patch' | null;
59
59
  skills: Array<SkillStaleness>;
60
+ signals: Array<StalenessSignal>;
60
61
  }
61
62
  interface SkillStaleness {
62
63
  name: string;
63
64
  reasons: Array<string>;
64
65
  needsReview: boolean;
65
66
  }
67
+ interface StalenessSignal {
68
+ type: string;
69
+ library?: string;
70
+ subject?: string;
71
+ reasons: Array<string>;
72
+ needsReview: boolean;
73
+ artifactPath?: string;
74
+ packageName?: string;
75
+ packageRoot?: string;
76
+ skill?: string;
77
+ }
78
+ interface IntentArtifactSet {
79
+ root: string;
80
+ artifactsDir: string;
81
+ skillTrees: Array<IntentArtifactFile>;
82
+ domainMaps: Array<IntentArtifactFile>;
83
+ skills: Array<IntentArtifactSkill>;
84
+ ignoredPackages: Array<IntentArtifactCoverageIgnore>;
85
+ warnings: Array<IntentArtifactWarning>;
86
+ }
87
+ interface IntentArtifactFile {
88
+ path: string;
89
+ kind: 'skill-tree' | 'domain-map';
90
+ libraryName?: string;
91
+ libraryVersion?: string;
92
+ }
93
+ interface IntentArtifactSkill {
94
+ artifactPath: string;
95
+ artifactKind: 'skill-tree' | 'domain-map';
96
+ name?: string;
97
+ slug?: string;
98
+ path?: string;
99
+ package?: string;
100
+ packages: Array<string>;
101
+ sources: Array<string>;
102
+ covers: Array<string>;
103
+ }
104
+ interface IntentArtifactCoverageIgnore {
105
+ packageName: string;
106
+ reason?: string;
107
+ artifactPath: string;
108
+ }
109
+ interface IntentArtifactWarning {
110
+ artifactPath: string;
111
+ message: string;
112
+ }
66
113
  interface FeedbackPayload {
67
114
  skill: string;
68
115
  package: string;
@@ -96,4 +143,4 @@ interface IntentProjectConfig {
96
143
  };
97
144
  }
98
145
  //#endregion
99
- export { IntentProjectConfig as a, ScanOptions as c, SkillStaleness as d, StalenessReport as f, IntentPackage as i, ScanResult as l, FeedbackPayload as n, MetaFeedbackPayload as o, VersionConflict as p, IntentConfig as r, MetaSkillName as s, AgentName as t, SkillEntry as u };
146
+ export { StalenessReport as _, IntentArtifactSet as a, IntentConfig as c, MetaFeedbackPayload as d, MetaSkillName as f, SkillStaleness as g, SkillEntry as h, IntentArtifactFile as i, IntentPackage as l, ScanResult as m, FeedbackPayload as n, IntentArtifactSkill as o, ScanOptions as p, IntentArtifactCoverageIgnore as r, IntentArtifactWarning as s, AgentName as t, IntentProjectConfig as u, StalenessSignal as v, VersionConflict as y };