@trackunit/iris-app 1.21.9 → 1.21.12

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/CHANGELOG.md CHANGED
@@ -1,3 +1,33 @@
1
+ ## 1.21.12 (2026-05-28)
2
+
3
+ ### 🧱 Updated Dependencies
4
+
5
+ - Updated iris-app-build-utilities to 1.18.10
6
+ - Updated iris-app-api to 1.20.10
7
+ - Updated react-vite-test-setup to 0.0.10
8
+ - Updated shared-utils to 1.15.9
9
+
10
+ ## 1.21.11 (2026-05-28)
11
+
12
+ ### 🩹 Fixes
13
+
14
+ - **iris-app-sdk:** preserve custom Claude skills symlinks ([0a394e8a976](https://github.com/Trackunit/manager/commit/0a394e8a976))
15
+ - **iris-app-sdk:** address PR #23363 review comments ([#23363](https://github.com/Trackunit/manager/issues/23363))
16
+
17
+ ### ❤️ Thank You
18
+
19
+ - Cursor @cursoragent
20
+ - kla-trackunit
21
+
22
+ ## 1.21.10 (2026-05-27)
23
+
24
+ ### 🧱 Updated Dependencies
25
+
26
+ - Updated iris-app-build-utilities to 1.18.9
27
+ - Updated iris-app-api to 1.20.9
28
+ - Updated react-vite-test-setup to 0.0.9
29
+ - Updated shared-utils to 1.15.8
30
+
1
31
  ## 1.21.9 (2026-05-26)
2
32
 
3
33
  ### 🧱 Updated Dependencies
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@trackunit/iris-app",
3
- "version": "1.21.9",
3
+ "version": "1.21.12",
4
4
  "license": "SEE LICENSE IN LICENSE.txt",
5
5
  "main": "src/index.js",
6
6
  "generators": "./generators.json",
@@ -23,8 +23,8 @@
23
23
  "@nx/react": "22.6.5",
24
24
  "@npmcli/arborist": "^9.1.9",
25
25
  "win-ca": "^3.5.1",
26
- "@trackunit/shared-utils": "1.15.7",
27
- "@trackunit/iris-app-api": "1.20.8",
26
+ "@trackunit/shared-utils": "1.15.9",
27
+ "@trackunit/iris-app-api": "1.20.10",
28
28
  "tslib": "^2.6.2",
29
29
  "@clack/prompts": "^1.0.0",
30
30
  "@npm/types": "^1.0.2",
@@ -1,7 +1,7 @@
1
- import { Tree } from "@nx/devkit";
1
+ import { GeneratorCallback, Tree } from "@nx/devkit";
2
2
  import { AiAgentSyncGeneratorSchema } from "./schema";
3
3
  /**
4
4
  * Syncs Cursor skills, AGENTS.md, CLAUDE.md, and AI agent configuration files.
5
5
  * Requires the SDK to be at the latest version before running.
6
6
  */
7
- export declare function aiAgentSyncGenerator(tree: Tree, options: AiAgentSyncGeneratorSchema): Promise<void>;
7
+ export declare function aiAgentSyncGenerator(tree: Tree, options: AiAgentSyncGeneratorSchema): Promise<GeneratorCallback>;
@@ -7,6 +7,7 @@ const devkit_exports_1 = require("nx/src/devkit-exports");
7
7
  const pacote = tslib_1.__importStar(require("pacote"));
8
8
  const path = tslib_1.__importStar(require("path"));
9
9
  const semver = tslib_1.__importStar(require("semver"));
10
+ const link_claude_skills_1 = require("../utils/link-claude-skills");
10
11
  const IRIS_APP_PACKAGE = "@trackunit/iris-app";
11
12
  const UPDATE_SCRIPT_NAME = "update:trackunit";
12
13
  const UPDATE_SCRIPT_CMD = 'npx npm-check-updates "/@trackunit/" -u';
@@ -103,5 +104,16 @@ async function aiAgentSyncGenerator(tree, options) {
103
104
  const rootTemplatePath = path.join(__dirname, "../preset/root-files");
104
105
  (0, devkit_1.generateFiles)(tree, rootTemplatePath, ".", {});
105
106
  await (0, devkit_1.formatFiles)(tree);
107
+ // After tree flush, create a symlink at .claude/skills -> ../.agents/skills
108
+ // so Claude Code auto-discovers the same skills Cursor and Codex consume.
109
+ // The Tree API has no symlink primitive, so this runs as a post-generation
110
+ // callback against the actual filesystem.
111
+ return () => {
112
+ const result = (0, link_claude_skills_1.linkClaudeSkills)(tree.root);
113
+ if (result.status === "skipped") {
114
+ devkit_1.logger.warn(`[iris-app:ai-agent-sync] Skipped creating .claude/skills symlink: ${result.reason}. ` +
115
+ `Claude Code users may need to create it manually: ln -s ../.agents/skills .claude/skills`);
116
+ }
117
+ };
106
118
  }
107
119
  //# sourceMappingURL=generator.js.map
@@ -6,6 +6,7 @@ const devkit_1 = require("@nx/devkit");
6
6
  const js_1 = require("@nx/js");
7
7
  const react_1 = require("@nx/react");
8
8
  const path_1 = tslib_1.__importDefault(require("path"));
9
+ const link_claude_skills_1 = require("../utils/link-claude-skills");
9
10
  /**
10
11
  * Preset generator for Iris apps workspace.
11
12
  * Use with create-nx-workspace to create a new workspace for developing Iris apps.
@@ -56,7 +57,16 @@ async function presetGenerator(tree, options) {
56
57
  });
57
58
  // This react generator adds react 19 and react-dom 19 to the package.json if we don't add react 18 above.
58
59
  const initReact = await (0, react_1.reactInitGenerator)(tree, {});
59
- return (0, devkit_1.runTasksInSerial)(jsInitTask, initReact);
60
+ // Post-flush task: symlink .claude/skills -> ../.agents/skills so Claude Code
61
+ // auto-discovers the same skills as Cursor/Codex without manual setup.
62
+ const linkSkillsTask = () => {
63
+ const result = (0, link_claude_skills_1.linkClaudeSkills)(tree.root);
64
+ if (result.status === "skipped") {
65
+ devkit_1.logger.warn(`[iris-app:preset] Skipped creating .claude/skills symlink: ${result.reason}. ` +
66
+ `Claude Code users may need to create it manually: ln -s ../.agents/skills .claude/skills`);
67
+ }
68
+ };
69
+ return (0, devkit_1.runTasksInSerial)(jsInitTask, initReact, linkSkillsTask);
60
70
  }
61
71
  function updateWorkspaceLayout(tree) {
62
72
  const nxJson = (0, devkit_1.readNxJson)(tree) ?? {};
@@ -6,12 +6,12 @@ This is an IrisX App project generated by the Trackunit SDK. Follow AGENTS.md fo
6
6
 
7
7
  ## Skills
8
8
 
9
- SDK-specific skills are located in `.agents/skills/`. When a skill is referenced in AGENTS.md, read it from `.agents/skills/[skill-name]/SKILL.md`.
9
+ SDK-specific skills live in `.agents/skills/`. The generator creates a `.claude/skills` symlink pointing at `../.agents/skills` so Claude Code auto-discovers them. When a skill is referenced in AGENTS.md, read it from `.agents/skills/[skill-name]/SKILL.md`.
10
10
 
11
- If skills from `.agents/skills/` are not appearing in your available skills list, suggest the user symlink them for automatic discovery:
11
+ If skills are not appearing in your available skills list, the symlink may be missing (for example on Windows without Developer Mode, or if a real `.claude/skills` directory existed first). Recreate it with:
12
12
 
13
13
  ```bash
14
- ln -s .agents/skills .claude/skills
14
+ ln -s ../.agents/skills .claude/skills
15
15
  ```
16
16
 
17
- Note: If the user already has a `.claude/skills` folder, they should symlink individual skills or the contents instead.
17
+ If `.claude/skills` already exists as a real directory, move its contents into `.agents/skills/` and delete it before running the command above.
@@ -0,0 +1,18 @@
1
+ export type LinkClaudeSkillsResult = {
2
+ status: "created";
3
+ } | {
4
+ status: "already-linked";
5
+ } | {
6
+ status: "skipped";
7
+ reason: string;
8
+ };
9
+ /**
10
+ * Ensures `.claude/skills` is a symlink to `../.agents/skills` so Claude Code
11
+ * auto-discovers skills shared via `.agents/skills`.
12
+ *
13
+ * Idempotent: leaves an existing valid symlink alone, refuses to overwrite a
14
+ * real `.claude/skills` directory or file. Cross-platform-safe: catches
15
+ * symlink permission errors (e.g. Windows without Developer Mode) and returns
16
+ * a `skipped` result instead of throwing.
17
+ */
18
+ export declare function linkClaudeSkills(workspaceRoot: string): LinkClaudeSkillsResult;
@@ -0,0 +1,72 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.linkClaudeSkills = linkClaudeSkills;
4
+ const tslib_1 = require("tslib");
5
+ const fs = tslib_1.__importStar(require("fs"));
6
+ const path = tslib_1.__importStar(require("path"));
7
+ const CLAUDE_DIR = ".claude";
8
+ const CLAUDE_SKILLS_NAME = "skills";
9
+ const AGENTS_SKILLS_REL = path.join("..", ".agents", "skills");
10
+ /**
11
+ * Ensures `.claude/skills` is a symlink to `../.agents/skills` so Claude Code
12
+ * auto-discovers skills shared via `.agents/skills`.
13
+ *
14
+ * Idempotent: leaves an existing valid symlink alone, refuses to overwrite a
15
+ * real `.claude/skills` directory or file. Cross-platform-safe: catches
16
+ * symlink permission errors (e.g. Windows without Developer Mode) and returns
17
+ * a `skipped` result instead of throwing.
18
+ */
19
+ function linkClaudeSkills(workspaceRoot) {
20
+ const claudeDir = path.join(workspaceRoot, CLAUDE_DIR);
21
+ const linkPath = path.join(claudeDir, CLAUDE_SKILLS_NAME);
22
+ const agentsSkillsAbs = path.join(workspaceRoot, ".agents", "skills");
23
+ if (!fs.existsSync(agentsSkillsAbs)) {
24
+ return { status: "skipped", reason: ".agents/skills does not exist" };
25
+ }
26
+ fs.mkdirSync(claudeDir, { recursive: true });
27
+ const existingLstat = safeLstat(linkPath);
28
+ if (existingLstat?.isSymbolicLink()) {
29
+ const currentTarget = fs.readlinkSync(linkPath);
30
+ if (resolveSymlinkTarget({
31
+ currentTarget,
32
+ linkParentPath: claudeDir,
33
+ }) === path.resolve(agentsSkillsAbs)) {
34
+ return { status: "already-linked" };
35
+ }
36
+ return {
37
+ status: "skipped",
38
+ reason: `.claude/skills already exists as a symlink to ${currentTarget}`,
39
+ };
40
+ }
41
+ else if (existingLstat) {
42
+ return {
43
+ status: "skipped",
44
+ reason: `.claude/skills already exists as a ${existingLstat.isDirectory() ? "directory" : "file"}`,
45
+ };
46
+ }
47
+ try {
48
+ fs.symlinkSync(AGENTS_SKILLS_REL, linkPath, "dir");
49
+ return { status: "created" };
50
+ }
51
+ catch (error) {
52
+ return {
53
+ status: "skipped",
54
+ reason: `failed to create symlink: ${error instanceof Error ? error.message : String(error)}`,
55
+ };
56
+ }
57
+ }
58
+ function safeLstat(p) {
59
+ try {
60
+ return fs.lstatSync(p);
61
+ }
62
+ catch {
63
+ return undefined;
64
+ }
65
+ }
66
+ function resolveSymlinkTarget({ currentTarget, linkParentPath }) {
67
+ if (path.isAbsolute(currentTarget)) {
68
+ return path.resolve(currentTarget);
69
+ }
70
+ return path.resolve(linkParentPath, currentTarget);
71
+ }
72
+ //# sourceMappingURL=link-claude-skills.js.map