@mikulgohil/ai-kit 1.8.1 → 1.10.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -74,6 +74,7 @@ Scans your `package.json`, config files, and directory structure to detect your
74
74
  |---|---|
75
75
  | Next.js 15 with App Router | Server Components, Server Actions, `app/` routing patterns |
76
76
  | Sitecore XM Cloud | `<Text>`, `<RichText>`, `<Image>` field helpers, placeholder patterns |
77
+ | Optimizely SaaS CMS | Visual Builder, Optimizely Graph, `@remkoj` SDK, component factory |
77
78
  | Tailwind CSS v4 | `@theme` tokens, utility class patterns, responsive prefixes |
78
79
  | TypeScript strict mode | No `any`, proper null checks, discriminated unions |
79
80
  | Turborepo monorepo | Workspace conventions, cross-package imports |
@@ -2,6 +2,8 @@
2
2
  name: build-resolver
3
3
  description: Build error resolution agent — diagnoses and fixes Next.js, TypeScript, and Sitecore build errors.
4
4
  tools: Read, Edit, Glob, Grep, Bash
5
+ isolation: worktree
6
+ initialPrompt: Run the build command from package.json and diagnose any errors found.
5
7
  ---
6
8
 
7
9
  # Build Error Resolver
@@ -2,6 +2,8 @@
2
2
  name: e2e-runner
3
3
  description: Playwright E2E test agent — generates and runs Playwright tests using Page Object Model for Next.js applications.
4
4
  tools: Read, Write, Edit, Glob, Grep, Bash
5
+ isolation: worktree
6
+ initialPrompt: Analyze existing test coverage and identify critical user flows that need E2E tests.
5
7
  ---
6
8
 
7
9
  # E2E Test Runner
@@ -1,7 +1,9 @@
1
1
  ---
2
2
  name: migration-specialist
3
3
  description: Migration specialist agent — framework upgrades, breaking change detection, codemods, dependency migration, and incremental adoption strategies.
4
- tools: Read, Glob, Grep, Bash
4
+ tools: Read, Edit, Glob, Grep, Bash
5
+ isolation: worktree
6
+ initialPrompt: Audit the current dependency versions and identify available upgrades with breaking changes.
5
7
  ---
6
8
 
7
9
  # Migration Specialist
@@ -2,6 +2,8 @@
2
2
  name: refactor-cleaner
3
3
  description: Dead code cleanup and refactoring agent — finds unused exports, cleans imports, and removes dead code.
4
4
  tools: Read, Edit, Glob, Grep, Bash
5
+ isolation: worktree
6
+ initialPrompt: Scan for dead code and unused exports in this project using Knip or manual analysis.
5
7
  ---
6
8
 
7
9
  # Refactor & Cleanup Agent
@@ -0,0 +1,90 @@
1
+ # Fetch Docs
2
+
3
+ > **Role**: You are a documentation researcher. Your job is to fetch the latest, version-specific documentation for this project's tech stack and summarize it into the conversation context so all subsequent coding is informed by current APIs.
4
+ > **Goal**: Pre-load current documentation for the detected frameworks so the AI doesn't rely on potentially outdated training data.
5
+
6
+ ## Mandatory Steps
7
+
8
+ You MUST follow these steps in order. Do not skip any step.
9
+
10
+ 1. **Detect the Stack** — Read `ai-kit.config.json` (or `package.json` if config doesn't exist) to identify:
11
+ - Framework and version (e.g., Next.js 16.2.2)
12
+ - CMS and version (e.g., Sitecore Content SDK v2.x, Optimizely SaaS)
13
+ - Styling framework (e.g., Tailwind CSS v4)
14
+ - Any other key libraries in dependencies
15
+
16
+ 2. **Fetch Documentation** — For each detected framework, fetch current docs using the best available method:
17
+
18
+ **Next.js**:
19
+ - Primary: Use Context7 MCP → `resolve-library-id` for "next.js" → `query-docs` for the specific topic
20
+ - Fallback: WebFetch `https://nextjs.org/docs/llms-full.txt` (AI-optimized full docs)
21
+ - Focus on: App Router APIs, Server Components, Server Actions, Middleware, ISR, Turbopack (if v16+)
22
+
23
+ **Tailwind CSS**:
24
+ - Primary: Use Context7 MCP → `resolve-library-id` for "tailwindcss" → `query-docs`
25
+ - Focus on: v4 `@theme` syntax (if v4 detected), utility classes, responsive patterns, plugin API
26
+
27
+ **Sitecore XM Cloud / Content SDK**:
28
+ - Primary: Use Context7 MCP → `resolve-library-id` for "sitecore" → `query-docs`
29
+ - Fallback: Check project repo for `LLMs.txt` file
30
+ - Focus on: Component bindings, field helpers, Experience Edge GraphQL, personalization
31
+
32
+ **React**:
33
+ - Primary: Use Context7 MCP → `resolve-library-id` for "react" → `query-docs`
34
+ - Focus on: React 19 APIs (useActionState, use, Server Components), hooks rules
35
+
36
+ **Other libraries** (if specified in $ARGUMENTS):
37
+ - Use Context7 MCP → `resolve-library-id` → `query-docs`
38
+
39
+ 3. **Summarize Key APIs** — For each framework, produce a concise summary:
40
+ - Current stable version
41
+ - Key API changes since the AI's likely training cutoff
42
+ - API signatures for commonly used functions
43
+ - Breaking changes or deprecations to watch for
44
+ - Code examples from the official docs
45
+
46
+ 4. **Report What Was Loaded** — Print a summary table:
47
+
48
+ ## Output Format
49
+
50
+ ```
51
+ ## Documentation Loaded
52
+
53
+ | Framework | Version | Source | Key APIs Fetched |
54
+ |-----------|---------|--------|-----------------|
55
+ | Next.js | 16.2.x | Context7 | App Router, Server Actions, Turbopack |
56
+ | Tailwind | 4.x | Context7 | @theme syntax, utility classes |
57
+ | Sitecore | SDK v2.x | LLMs.txt | Field helpers, Experience Edge |
58
+
59
+ ## Key API Reference
60
+
61
+ ### Next.js 16
62
+ [Concise API reference with signatures and examples]
63
+
64
+ ### Tailwind CSS v4
65
+ [Key patterns and syntax differences from v3]
66
+
67
+ ### Sitecore Content SDK v2.x
68
+ [Component patterns and field helper usage]
69
+
70
+ ## What's New Since Training Cutoff
71
+ [Notable changes the AI might not know about]
72
+ ```
73
+
74
+ ## Rules
75
+
76
+ - ALWAYS check Context7 MCP first — it's the fastest and most reliable source
77
+ - If Context7 is not available, use WebFetch against official docs
78
+ - Keep summaries concise — focus on API signatures and patterns, not tutorials
79
+ - Highlight breaking changes and deprecations prominently
80
+ - If a specific library is passed as $ARGUMENTS, fetch docs for that library too
81
+ - Do NOT skip any detected framework — even if you think you know the APIs
82
+
83
+ ## When to Use This Skill
84
+
85
+ - At the **start of a coding session** — run once to pre-load context
86
+ - Before **major framework upgrades** — fetch docs for both current and target versions
87
+ - When you encounter **unexpected API behavior** — refresh docs for the specific library
88
+ - When working with **niche libraries** (Sitecore, Optimizely) that models know less about
89
+
90
+ Target: $ARGUMENTS
package/dist/index.js CHANGED
@@ -15,7 +15,7 @@ var GUIDES_DIR = path.join(PACKAGE_ROOT, "guides");
15
15
  var DOCS_SCAFFOLDS_DIR = path.join(PACKAGE_ROOT, "docs-scaffolds");
16
16
  var AGENTS_DIR = path.join(PACKAGE_ROOT, "agents");
17
17
  var CONTEXTS_DIR = path.join(PACKAGE_ROOT, "contexts");
18
- var VERSION = "1.8.0";
18
+ var VERSION = "1.10.0";
19
19
  var AI_KIT_CONFIG_FILE = "ai-kit.config.json";
20
20
  var GENERATED_FILES = {
21
21
  claudeMd: "CLAUDE.md",
@@ -34,6 +34,7 @@ var TEMPLATE_FRAGMENTS = [
34
34
  "nextjs-app-router",
35
35
  "nextjs-pages-router",
36
36
  "sitecore-xmc",
37
+ "optimizely-saas",
37
38
  "tailwind",
38
39
  "typescript",
39
40
  "monorepo",
@@ -117,13 +118,14 @@ function detectNextjs(projectPath, pkg) {
117
118
  return { framework: "unknown" };
118
119
  }
119
120
  const nextjsVersion = deps.next.replace(/[\^~>=<]/g, "");
121
+ const nextjsMajorVersion = parseInt(nextjsVersion.split(".")[0], 10) || void 0;
120
122
  const hasAppDir = dirExists(path2.join(projectPath, "app")) || dirExists(path2.join(projectPath, "src", "app"));
121
123
  const hasPagesDir = dirExists(path2.join(projectPath, "pages")) || dirExists(path2.join(projectPath, "src", "pages"));
122
124
  let routerType;
123
125
  if (hasAppDir && hasPagesDir) routerType = "hybrid";
124
126
  else if (hasAppDir) routerType = "app";
125
127
  else if (hasPagesDir) routerType = "pages";
126
- return { framework: "nextjs", nextjsVersion, routerType };
128
+ return { framework: "nextjs", nextjsVersion, nextjsMajorVersion, routerType };
127
129
  }
128
130
 
129
131
  // src/scanner/sitecore.ts
@@ -153,6 +155,56 @@ function detectSitecore(pkg) {
153
155
  return { cms: "none" };
154
156
  }
155
157
 
158
+ // src/scanner/optimizely.ts
159
+ var OPTIMIZELY_PACKAGES = [
160
+ "@remkoj/optimizely-cms-react",
161
+ "@remkoj/optimizely-cms-nextjs",
162
+ "@remkoj/optimizely-cms-api",
163
+ "@remkoj/optimizely-cms-cli",
164
+ "@remkoj/optimizely-graph-client",
165
+ "@remkoj/optimizely-graph-cli",
166
+ "@remkoj/optimizely-graph-functions",
167
+ "@remkoj/optimizely-one-nextjs"
168
+ ];
169
+ var OPTIMIZELY_OFFICIAL_PACKAGES = [
170
+ "@optimizely/cms",
171
+ "@optimizely/graph",
172
+ "@optimizely/cms-react",
173
+ "@optimizely/cms-nextjs"
174
+ ];
175
+ function detectOptimizely(pkg) {
176
+ const deps = {
177
+ ...pkg.dependencies,
178
+ ...pkg.devDependencies
179
+ };
180
+ const foundPackages = [];
181
+ let version;
182
+ for (const pkgName of OPTIMIZELY_PACKAGES) {
183
+ if (deps[pkgName]) {
184
+ foundPackages.push(pkgName);
185
+ if (!version && (pkgName === "@remkoj/optimizely-cms-nextjs" || pkgName === "@remkoj/optimizely-cms-react")) {
186
+ version = deps[pkgName].replace(/[\^~>=<]/g, "");
187
+ }
188
+ }
189
+ }
190
+ for (const pkgName of OPTIMIZELY_OFFICIAL_PACKAGES) {
191
+ if (deps[pkgName]) {
192
+ foundPackages.push(pkgName);
193
+ if (!version) {
194
+ version = deps[pkgName].replace(/[\^~>=<]/g, "");
195
+ }
196
+ }
197
+ }
198
+ if (foundPackages.length === 0 && deps["@remkoj/optimizely-graph-functions"]) {
199
+ foundPackages.push("@remkoj/optimizely-graph-functions");
200
+ }
201
+ return {
202
+ optimizelySaas: foundPackages.length > 0,
203
+ optimizelyVersion: version || void 0,
204
+ optimizelyPackages: foundPackages
205
+ };
206
+ }
207
+
156
208
  // src/scanner/styling.ts
157
209
  import path3 from "path";
158
210
  function detectStyling(projectPath, pkg) {
@@ -709,6 +761,7 @@ async function scanProject(projectPath) {
709
761
  const projectName = pkg.name || path13.basename(projectPath);
710
762
  const nextjsResult = detectNextjs(projectPath, pkg);
711
763
  const sitecoreResult = detectSitecore(pkg);
764
+ const optimizelyResult = detectOptimizely(pkg);
712
765
  const stylingResult = detectStyling(projectPath, pkg);
713
766
  const tsResult = detectTypescript(projectPath);
714
767
  const monorepoResult = detectMonorepo(projectPath, pkg);
@@ -720,9 +773,14 @@ async function scanProject(projectPath) {
720
773
  const staticSiteResult = detectStaticSite(projectPath, pkg);
721
774
  const aiIgnorePatterns = loadAiIgnorePatterns(projectPath);
722
775
  const figmaDetected = figmaResult.figmaMcp || figmaResult.figmaCodeCli || figmaResult.designTokens;
776
+ const cmsResult = sitecoreResult.cms !== "none" ? sitecoreResult : optimizelyResult.optimizelySaas ? {
777
+ cms: "optimizely-saas",
778
+ optimizelyVersion: optimizelyResult.optimizelyVersion,
779
+ optimizelyPackages: optimizelyResult.optimizelyPackages
780
+ } : sitecoreResult;
723
781
  return {
724
782
  ...nextjsResult,
725
- ...sitecoreResult,
783
+ ...cmsResult,
726
784
  ...stylingResult,
727
785
  ...tsResult,
728
786
  ...monorepoResult,
@@ -817,7 +875,9 @@ function selectFragments(scan) {
817
875
  fragments.push("nextjs-pages-router");
818
876
  }
819
877
  }
820
- if (scan.cms !== "none") {
878
+ if (scan.cms === "optimizely-saas") {
879
+ fragments.push("optimizely-saas");
880
+ } else if (scan.cms !== "none") {
821
881
  fragments.push("sitecore-xmc");
822
882
  }
823
883
  if (scan.styling.includes("tailwind")) {
@@ -851,7 +911,11 @@ function buildVariables(scan) {
851
911
  techStack.push(`Next.js ${scan.nextjsVersion || ""}`);
852
912
  }
853
913
  if (scan.cms !== "none") {
854
- if (scan.cms === "sitecore-xmc-v2") {
914
+ if (scan.cms === "optimizely-saas") {
915
+ techStack.push(
916
+ `Optimizely SaaS CMS${scan.optimizelyVersion ? ` (SDK ${scan.optimizelyVersion})` : ""}`
917
+ );
918
+ } else if (scan.cms === "sitecore-xmc-v2") {
855
919
  techStack.push(
856
920
  `Sitecore XM Cloud${scan.sitecoreContentSdkVersion ? ` (Content SDK ${scan.sitecoreContentSdkVersion})` : " (Content SDK v2)"}`
857
921
  );
@@ -920,9 +984,13 @@ function buildCursorVariables(scan) {
920
984
  techStack.push(`Next.js ${scan.nextjsVersion || ""}`);
921
985
  }
922
986
  if (scan.cms !== "none") {
923
- techStack.push(
924
- scan.cms === "sitecore-xmc-v2" || scan.cms === "sitecore-xmc" ? "Sitecore XM Cloud" : "Sitecore JSS"
925
- );
987
+ if (scan.cms === "optimizely-saas") {
988
+ techStack.push("Optimizely SaaS CMS");
989
+ } else {
990
+ techStack.push(
991
+ scan.cms === "sitecore-xmc-v2" || scan.cms === "sitecore-xmc" ? "Sitecore XM Cloud" : "Sitecore JSS"
992
+ );
993
+ }
926
994
  }
927
995
  if (scan.typescript) techStack.push("TypeScript");
928
996
  if (scan.styling.includes("tailwind")) techStack.push("Tailwind CSS");
@@ -958,6 +1026,10 @@ var MDC_CONFIG = {
958
1026
  description: "Sitecore XM Cloud component patterns and field helpers",
959
1027
  globs: "src/components/**/*.{ts,tsx}"
960
1028
  },
1029
+ "optimizely-saas": {
1030
+ description: "Optimizely SaaS CMS patterns, Visual Builder, and Graph API",
1031
+ globs: "src/components/**/*.{ts,tsx}, src/gql/**/*.{ts,graphql}"
1032
+ },
961
1033
  tailwind: {
962
1034
  description: "Tailwind CSS conventions and utility patterns",
963
1035
  globs: "**/*.{tsx,jsx,css}"
@@ -982,7 +1054,7 @@ var MDC_CONFIG = {
982
1054
  function generateMdcFiles(scan) {
983
1055
  const fragments = selectFragments(scan);
984
1056
  const variables = buildCursorVariables(scan);
985
- return fragments.map((fragment) => {
1057
+ const mdcFiles = fragments.map((fragment) => {
986
1058
  const config = MDC_CONFIG[fragment] || {
987
1059
  description: fragment,
988
1060
  globs: "**/*"
@@ -1005,6 +1077,42 @@ function generateMdcFiles(scan) {
1005
1077
  ${replaced}`
1006
1078
  };
1007
1079
  });
1080
+ const techStack = [
1081
+ scan.framework === "nextjs" ? `Next.js ${scan.nextjsVersion || ""}`.trim() : scan.framework,
1082
+ scan.cms !== "none" ? scan.cms : null,
1083
+ scan.styling.length > 0 ? scan.styling.join(", ") : null,
1084
+ scan.typescript ? "TypeScript" : null,
1085
+ scan.monorepo ? scan.monorepoTool : null
1086
+ ].filter(Boolean).join(" + ");
1087
+ const indexContent = [
1088
+ "---",
1089
+ `description: ${scan.projectName} \u2014 repo-wide project conventions and AI rules`,
1090
+ "globs: **/*",
1091
+ "alwaysApply: true",
1092
+ "---",
1093
+ "",
1094
+ `<!-- Generated by ai-kit v${VERSION} -->`,
1095
+ "",
1096
+ `# ${scan.projectName}`,
1097
+ "",
1098
+ `**Tech Stack**: ${techStack}`,
1099
+ "",
1100
+ "## Active Rules",
1101
+ ...fragments.map((f) => `- [\`${f}\`](./${f}.mdc) \u2014 ${MDC_CONFIG[f]?.description || f}`),
1102
+ "",
1103
+ "## Conventions",
1104
+ "- Follow existing patterns in the codebase",
1105
+ "- Match naming conventions already in use",
1106
+ `- Package manager: \`${scan.packageManager}\``,
1107
+ scan.routerType ? `- Router: ${scan.routerType === "app" ? "App Router" : scan.routerType === "pages" ? "Pages Router" : "Hybrid (App + Pages)"}` : "",
1108
+ "",
1109
+ "> Rules are auto-generated by [ai-kit](https://github.com/mikulgohil/ai-kit). Run `ai-kit update` to refresh."
1110
+ ].filter((line) => line !== void 0).join("\n");
1111
+ mdcFiles.unshift({
1112
+ filename: "index.mdc",
1113
+ content: indexContent
1114
+ });
1115
+ return mdcFiles;
1008
1116
  }
1009
1117
 
1010
1118
  // src/generator/config.ts
@@ -1032,6 +1140,7 @@ function generateHooks(scan, profile = "standard") {
1032
1140
  const hooks = {};
1033
1141
  const preToolUse = [];
1034
1142
  const postToolUse = [];
1143
+ const postCompact = [];
1035
1144
  const stop = [];
1036
1145
  preToolUse.push({
1037
1146
  matcher: "Bash(git push*)",
@@ -1206,6 +1315,25 @@ function generateHooks(scan, profile = "standard") {
1206
1315
  ]
1207
1316
  });
1208
1317
  }
1318
+ if (profile !== "minimal") {
1319
+ postCompact.push({
1320
+ matcher: "",
1321
+ hooks: [
1322
+ {
1323
+ type: "command",
1324
+ command: [
1325
+ 'echo "\u{1F504} Context was compacted. Key reminders:"',
1326
+ 'if [ -f "CLAUDE.md" ]; then echo " \u2192 CLAUDE.md is loaded \u2014 project rules are preserved"; fi',
1327
+ 'if [ -f "ai-kit.config.json" ]; then',
1328
+ ` STACK=$(node -e "try{const c=JSON.parse(require('fs').readFileSync('ai-kit.config.json','utf8'));console.log([c.scanResult.framework,c.scanResult.cms,c.scanResult.styling?.join(',')].filter(Boolean).join(' + '))}catch{}" 2>/dev/null)`,
1329
+ ' if [ -n "$STACK" ]; then echo " \u2192 Tech stack: $STACK"; fi',
1330
+ "fi",
1331
+ 'echo " \u2192 Run /effort to adjust reasoning depth if needed"'
1332
+ ].join("\n")
1333
+ }
1334
+ ]
1335
+ });
1336
+ }
1209
1337
  if (profile === "strict") {
1210
1338
  stop.push({
1211
1339
  matcher: "",
@@ -1219,6 +1347,7 @@ function generateHooks(scan, profile = "standard") {
1219
1347
  }
1220
1348
  if (preToolUse.length > 0) hooks.PreToolUse = preToolUse;
1221
1349
  if (postToolUse.length > 0) hooks.PostToolUse = postToolUse;
1350
+ if (postCompact.length > 0) hooks.PostCompact = postCompact;
1222
1351
  if (stop.length > 0) hooks.Stop = stop;
1223
1352
  return hooks;
1224
1353
  }
@@ -1280,7 +1409,9 @@ var AVAILABLE_SKILLS = [
1280
1409
  "harness-audit",
1281
1410
  // New skills (v1.7.0) — requirements clarification (inspired by OMC Deep Interview)
1282
1411
  "deep-interview",
1283
- "clarify-requirements"
1412
+ "clarify-requirements",
1413
+ // New skills (v1.10.0) — documentation freshness
1414
+ "fetch-docs"
1284
1415
  ];
1285
1416
  var SKILL_DESCRIPTIONS = {
1286
1417
  "prompt-help": "Help developers write effective AI prompts with structured context",
@@ -1330,7 +1461,9 @@ var SKILL_DESCRIPTIONS = {
1330
1461
  "harness-audit": "Audit AI agent configuration \u2014 check CLAUDE.md, hooks, agents, skills, MCP servers",
1331
1462
  // New skills (v1.7.0) — requirements clarification
1332
1463
  "deep-interview": "Socratic requirements gathering \u2014 structured interview to transform vague ideas into detailed specifications",
1333
- "clarify-requirements": "Quick task clarification \u2014 identify gaps and ambiguities in under 5 minutes before coding"
1464
+ "clarify-requirements": "Quick task clarification \u2014 identify gaps and ambiguities in under 5 minutes before coding",
1465
+ // New skills (v1.10.0) — documentation freshness
1466
+ "fetch-docs": "Pre-load current, version-specific docs for your tech stack using Context7 MCP \u2014 run at session start to prevent outdated API usage"
1334
1467
  };
1335
1468
  async function copySkills(targetDir) {
1336
1469
  const copied = [];