@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 +30 -0
- package/package.json +3 -3
- package/src/generators/ai-agent-sync/generator.d.ts +2 -2
- package/src/generators/ai-agent-sync/generator.js +12 -0
- package/src/generators/preset/generator.js +11 -1
- package/src/generators/preset/root-files/CLAUDE.md +4 -4
- package/src/generators/utils/link-claude-skills.d.ts +18 -0
- package/src/generators/utils/link-claude-skills.js +72 -0
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.
|
|
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.
|
|
27
|
-
"@trackunit/iris-app-api": "1.20.
|
|
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<
|
|
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
|
-
|
|
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
|
|
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
|
|
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
|
|
14
|
+
ln -s ../.agents/skills .claude/skills
|
|
15
15
|
```
|
|
16
16
|
|
|
17
|
-
|
|
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
|