@trackunit/iris-app 2.9.2 → 2.10.1

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,30 @@
1
+ ## 2.10.1 (2026-10-05)
2
+
3
+ ### 🧱 Updated Dependencies
4
+
5
+ - Updated iris-app-build-utilities to 2.6.3
6
+ - Updated iris-app-api to 2.8.3
7
+ - Updated react-graphql-tools to 1.19.3
8
+
9
+ ## 2.10.0 (2026-10-01)
10
+
11
+ ### 🚀 Features
12
+
13
+ - **iris-app:** create-app skill confirms Trackunit MCP is authenticated [GLU-2538] ([2b21dee8eb1](https://github.com/Trackunit/manager/commit/2b21dee8eb1))
14
+ - **iris-app:** graphql skill explores schema via Trackunit MCP when connected [GLU-2538] ([9ae217eccee](https://github.com/Trackunit/manager/commit/9ae217eccee))
15
+ - **iris-app:** teach generated AGENTS.md to use Trackunit MCP with /llms.txt fallback [GLU-2537] ([8022f333614](https://github.com/Trackunit/manager/commit/8022f333614))
16
+
17
+ ### 🩹 Fixes
18
+
19
+ - **review:** graphql skill uses codegen as the schema check when MCP is not connected [GLU-2538] ([ed9fafa9f0e](https://github.com/Trackunit/manager/commit/ed9fafa9f0e))
20
+ - **review:** detect deferred MCP tools and use codegen as the GraphQL fallback check [GLU-2537] ([08bbd3ceb60](https://github.com/Trackunit/manager/commit/08bbd3ceb60))
21
+
22
+ ### ❤️ Thank You
23
+
24
+ - Claude
25
+ - Cursor @cursoragent
26
+ - Michael Buss Rønne
27
+
1
28
  ## 2.9.2 (2026-10-01)
2
29
 
3
30
  ### 🧱 Updated Dependencies
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@trackunit/iris-app",
3
- "version": "2.9.2",
3
+ "version": "2.10.1",
4
4
  "license": "SEE LICENSE IN LICENSE.txt",
5
5
  "main": "src/index.js",
6
6
  "generators": "./generators.json",
@@ -26,10 +26,10 @@
26
26
  "@nx/react": "23.1.0",
27
27
  "@npmcli/arborist": "^9.1.9",
28
28
  "win-ca": "^3.5.1",
29
- "@trackunit/iris-app-build-utilities": "2.6.2",
30
- "@trackunit/react-graphql-tools": "1.19.2",
29
+ "@trackunit/iris-app-build-utilities": "2.6.3",
30
+ "@trackunit/react-graphql-tools": "1.19.3",
31
31
  "@trackunit/shared-utils": "1.18.2",
32
- "@trackunit/iris-app-api": "2.8.2",
32
+ "@trackunit/iris-app-api": "2.8.3",
33
33
  "tslib": "^2.6.2",
34
34
  "@clack/prompts": "^1.8.1",
35
35
  "@npm/types": "^1.0.2",
@@ -51,6 +51,7 @@ Structure the plan as:
51
51
  - **Phase 1: Project Setup**
52
52
  - Create app with `@trackunit/iris-app:create`
53
53
  - Create extensions with `@trackunit/iris-app:extend`
54
+ - Confirm Trackunit MCP is connected and authenticated (fallbacks if not)
54
55
  - Start dev server in background
55
56
 
56
57
  - **Phase 2: Browser Verification (CRITICAL GATE)**
@@ -87,6 +88,10 @@ npx nx generate @trackunit/iris-app:create [app-name]
87
88
  npx nx g @trackunit/iris-app:extend --name=[extension-name] --app=[app-name] --directory=[feature] --type=[EXTENSION_TYPE]
88
89
  ```
89
90
 
91
+ **Confirm Trackunit MCP:**
92
+ - Confirm Trackunit MCP is connected and authenticated before assuming its tools exist, using the check in the "Trackunit MCP" section of `AGENTS.md`.
93
+ - If it is not connected, tell the user they can connect it (see `AGENTS.md`), then continue with the fallbacks listed there. Do not block or wait for authentication.
94
+
90
95
  **5. Start Development Server**
91
96
 
92
97
  ```bash
@@ -18,6 +18,18 @@ Trackunit exposes a GraphQL API with NX executors for code generation. Use `@tra
18
18
 
19
19
  **Not for:** Time series data (use `graphql-timeseries` skill).
20
20
 
21
+ ## Explore the Schema
22
+
23
+ Before writing a query or mutation, check whether Trackunit MCP is connected, using the check in the "Trackunit MCP" section of `AGENTS.md` (it also covers setup and authentication).
24
+
25
+ **If Trackunit MCP is connected:**
26
+ - Look up types and fields with `explore_introspect_gql_schema`
27
+ - Validate each query or mutation with `explore_validate_gql_query` before saving the `.graphql` file and running codegen
28
+
29
+ **If Trackunit MCP is not connected:** do not block or wait for authentication. Use the [Developer Hub GraphQL docs](https://developers.trackunit.com/docs/apps-and-extensions/overview/public-apis/graphql-api/) and the [GraphQL Explorer](https://apps.iris.trackunit.com/graphql-public-viewer/) to find types, write the `.graphql` file, then run the `graphql-hooks` codegen below. Codegen validates against the public schema, so fix any unknown field or type errors it reports before using the generated hooks.
30
+
31
+ Never invent schema fields; look them up with one of the sources above, and treat codegen errors as the final check.
32
+
21
33
  ## Setup
22
34
 
23
35
  ### Install GraphQL Tools
@@ -131,7 +143,7 @@ const { data } = useQuery(GetAssetsDocument, {
131
143
 
132
144
  ## References
133
145
 
134
- - [Calling Trackunit GraphQL API](https://developers.trackunit.com/docs/graphql-api)
146
+ - [Calling Trackunit GraphQL API](https://developers.trackunit.com/docs/apps-and-extensions/overview/public-apis/graphql-api/)
135
147
  - [Apollo useQuery documentation](https://www.apollographql.com/docs/react/data/queries)
136
148
  - [Apollo useMutation documentation](https://www.apollographql.com/docs/react/data/mutations)
137
149
  - [GraphQL Code Generator](https://the-guild.dev/graphql/codegen)
@@ -140,6 +152,7 @@ const { data } = useQuery(GetAssetsDocument, {
140
152
 
141
153
  | Mistake | Fix |
142
154
  |---------|-----|
155
+ | Guessing schema fields | Introspect via Trackunit MCP; otherwise use the Developer Hub docs and fix any unknown field errors from `graphql-hooks` codegen |
143
156
  | Using generic GraphQL libraries | Use `@trackunit/react-graphql-tools` only |
144
157
  | Missing hook generation | Run `nx run [project]:graphql-hooks` after adding `.graphql` files |
145
158
  | Wrong project name format | Use `[subdir-name]-[extension-name]` from `project.json` |
@@ -23,6 +23,7 @@ async function presetGenerator(tree, options) {
23
23
  tree.write(extensionsPath, "{}");
24
24
  }
25
25
  (0, devkit_1.generateFiles)(tree, path_1.default.join(__dirname, "files"), ".", {});
26
+ (0, devkit_1.generateFiles)(tree, path_1.default.join(__dirname, "root-files"), ".", {});
26
27
  if (!tree.exists("vitest.empty-stub.ts")) {
27
28
  tree.write("vitest.empty-stub.ts", "export default {};\n");
28
29
  }
@@ -1 +1 @@
1
- {"version":3,"file":"generator.js","sourceRoot":"","sources":["../../../../../../../libs/iris-app-sdk/iris-app/src/generators/preset/generator.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n Tree,\n addDependenciesToPackageJson,\n generateFiles,\n logger,\n readNxJson,\n runTasksInSerial,\n updateJson,\n updateNxJson,\n} from \"@nx/devkit\";\nimport { initGenerator as jsInitGenerator } from \"@nx/js\";\nimport { reactInitGenerator } from \"@nx/react\";\nimport path from \"path\";\nimport { getPackageManifest } from \"../utils/get-package-manifest\";\nimport { linkClaudeSkills } from \"../utils/link-claude-skills\";\nimport { PresetGeneratorSchema } from \"./schema\";\n\n/**\n * Preset generator for Iris apps workspace.\n * Use with create-nx-workspace to create a new workspace for developing Iris apps.\n * ```npx create-nx-workspace --preset=iris-app```\n */\nexport async function presetGenerator(tree: Tree, options: PresetGeneratorSchema) {\n // setup workspace\n updateWorkspaceLayout(tree);\n tree.write(\n \"apps/readme.md\",\n `# Apps\\n\\nThis folder contains all apps in the workspace.\\n\\nApps are the main entry point for the Iris App SDK.\\nCreate an app by running \\`nx g @trackunit/iris-app:create <app-name>\\`.`\n );\n tree.write(\n \"libs/readme.md\",\n `# Libs\\n\\nThis folder contains all libs in the workspace.\\nCreate a lib by running \\`nx g @trackunit/iris-app:extend <lib-name>\\`.`\n );\n\n const extensionsPath = \".vscode/extensions.json\";\n\n if (!tree.exists(extensionsPath)) {\n tree.write(extensionsPath, \"{}\");\n }\n\n generateFiles(tree, path.join(__dirname, \"files\"), \".\", {});\n if (!tree.exists(\"vitest.empty-stub.ts\")) {\n tree.write(\"vitest.empty-stub.ts\", \"export default {};\\n\");\n }\n\n updateJson(tree, extensionsPath, value => {\n if (!value.recommendations) {\n value.recommendations = [];\n }\n value.recommendations = value.recommendations.filter(\n (recommendation: string) => recommendation !== \"firsttris.vscode-jest-runner\"\n );\n value.recommendations.push(\n \"graphql.vscode-graphql\",\n \"graphql.vscode-graphql-syntax\",\n \"bradlc.vscode-tailwindcss\",\n \"vitest.explorer\"\n );\n return value;\n });\n\n const jsInitTask = await jsInitGenerator(tree, {\n ...options,\n tsConfigName: \"tsconfig.base.json\",\n skipFormat: true,\n });\n\n updateJson(tree, \"tsconfig.base.json\", (tsconfig: { compilerOptions?: Record<string, unknown> }) => {\n if (!tsconfig.compilerOptions) {\n tsconfig.compilerOptions = {};\n }\n tsconfig.compilerOptions.ignoreDeprecations = \"6.0\";\n tsconfig.compilerOptions.esModuleInterop = true;\n tsconfig.compilerOptions.resolveJsonModule = true;\n tsconfig.compilerOptions.moduleResolution = \"bundler\";\n return tsconfig;\n });\n\n // Ships the generator that upgrades every @trackunit/* dependency, so a new\n // workspace can run the documented upgrade flow without installing it first.\n const migrationsVersion = (await getPackageManifest(\"@trackunit/migrations\")).version;\n\n addDependenciesToPackageJson(\n tree,\n {\n react: \"19.3.0\",\n \"react-dom\": \"19.3.0\",\n },\n {\n \"@trackunit/migrations\": migrationsVersion,\n }\n );\n\n // This react generator adds react 19 and react-dom 19 to the package.json if we don't add react 18 above.\n const initReact = await reactInitGenerator(tree, {});\n\n // Post-flush task: symlink .claude/skills -> ../.agents/skills so Claude Code\n // auto-discovers the same skills as Cursor/Codex without manual setup.\n const linkSkillsTask = () => {\n const result = linkClaudeSkills(tree.root);\n if (result.status === \"skipped\") {\n logger.warn(\n `[iris-app:preset] Skipped creating .claude/skills symlink: ${result.reason}. ` +\n `Claude Code users may need to create it manually: ln -s ../.agents/skills .claude/skills`\n );\n }\n };\n\n return runTasksInSerial(jsInitTask, initReact, linkSkillsTask);\n}\n\nfunction updateWorkspaceLayout(tree: Tree) {\n const nxJson = readNxJson(tree) ?? {};\n nxJson.workspaceLayout = {\n libsDir: \"libs\",\n appsDir: \"apps\",\n };\n updateNxJson(tree, nxJson);\n}\n"]}
1
+ {"version":3,"file":"generator.js","sourceRoot":"","sources":["../../../../../../../libs/iris-app-sdk/iris-app/src/generators/preset/generator.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n Tree,\n addDependenciesToPackageJson,\n generateFiles,\n logger,\n readNxJson,\n runTasksInSerial,\n updateJson,\n updateNxJson,\n} from \"@nx/devkit\";\nimport { initGenerator as jsInitGenerator } from \"@nx/js\";\nimport { reactInitGenerator } from \"@nx/react\";\nimport path from \"path\";\nimport { getPackageManifest } from \"../utils/get-package-manifest\";\nimport { linkClaudeSkills } from \"../utils/link-claude-skills\";\nimport { PresetGeneratorSchema } from \"./schema\";\n\n/**\n * Preset generator for Iris apps workspace.\n * Use with create-nx-workspace to create a new workspace for developing Iris apps.\n * ```npx create-nx-workspace --preset=iris-app```\n */\nexport async function presetGenerator(tree: Tree, options: PresetGeneratorSchema) {\n // setup workspace\n updateWorkspaceLayout(tree);\n tree.write(\n \"apps/readme.md\",\n `# Apps\\n\\nThis folder contains all apps in the workspace.\\n\\nApps are the main entry point for the Iris App SDK.\\nCreate an app by running \\`nx g @trackunit/iris-app:create <app-name>\\`.`\n );\n tree.write(\n \"libs/readme.md\",\n `# Libs\\n\\nThis folder contains all libs in the workspace.\\nCreate a lib by running \\`nx g @trackunit/iris-app:extend <lib-name>\\`.`\n );\n\n const extensionsPath = \".vscode/extensions.json\";\n\n if (!tree.exists(extensionsPath)) {\n tree.write(extensionsPath, \"{}\");\n }\n\n generateFiles(tree, path.join(__dirname, \"files\"), \".\", {});\n generateFiles(tree, path.join(__dirname, \"root-files\"), \".\", {});\n if (!tree.exists(\"vitest.empty-stub.ts\")) {\n tree.write(\"vitest.empty-stub.ts\", \"export default {};\\n\");\n }\n\n updateJson(tree, extensionsPath, value => {\n if (!value.recommendations) {\n value.recommendations = [];\n }\n value.recommendations = value.recommendations.filter(\n (recommendation: string) => recommendation !== \"firsttris.vscode-jest-runner\"\n );\n value.recommendations.push(\n \"graphql.vscode-graphql\",\n \"graphql.vscode-graphql-syntax\",\n \"bradlc.vscode-tailwindcss\",\n \"vitest.explorer\"\n );\n return value;\n });\n\n const jsInitTask = await jsInitGenerator(tree, {\n ...options,\n tsConfigName: \"tsconfig.base.json\",\n skipFormat: true,\n });\n\n updateJson(tree, \"tsconfig.base.json\", (tsconfig: { compilerOptions?: Record<string, unknown> }) => {\n if (!tsconfig.compilerOptions) {\n tsconfig.compilerOptions = {};\n }\n tsconfig.compilerOptions.ignoreDeprecations = \"6.0\";\n tsconfig.compilerOptions.esModuleInterop = true;\n tsconfig.compilerOptions.resolveJsonModule = true;\n tsconfig.compilerOptions.moduleResolution = \"bundler\";\n return tsconfig;\n });\n\n // Ships the generator that upgrades every @trackunit/* dependency, so a new\n // workspace can run the documented upgrade flow without installing it first.\n const migrationsVersion = (await getPackageManifest(\"@trackunit/migrations\")).version;\n\n addDependenciesToPackageJson(\n tree,\n {\n react: \"19.3.0\",\n \"react-dom\": \"19.3.0\",\n },\n {\n \"@trackunit/migrations\": migrationsVersion,\n }\n );\n\n // This react generator adds react 19 and react-dom 19 to the package.json if we don't add react 18 above.\n const initReact = await reactInitGenerator(tree, {});\n\n // Post-flush task: symlink .claude/skills -> ../.agents/skills so Claude Code\n // auto-discovers the same skills as Cursor/Codex without manual setup.\n const linkSkillsTask = () => {\n const result = linkClaudeSkills(tree.root);\n if (result.status === \"skipped\") {\n logger.warn(\n `[iris-app:preset] Skipped creating .claude/skills symlink: ${result.reason}. ` +\n `Claude Code users may need to create it manually: ln -s ../.agents/skills .claude/skills`\n );\n }\n };\n\n return runTasksInSerial(jsInitTask, initReact, linkSkillsTask);\n}\n\nfunction updateWorkspaceLayout(tree: Tree) {\n const nxJson = readNxJson(tree) ?? {};\n nxJson.workspaceLayout = {\n libsDir: \"libs\",\n appsDir: \"apps\",\n };\n updateNxJson(tree, nxJson);\n}\n"]}
@@ -17,6 +17,25 @@ When building any feature:
17
17
  3. If available, use the GraphQL API
18
18
  4. If not available, ask the user
19
19
 
20
+ ## Trackunit MCP
21
+
22
+ This workspace configures the Trackunit MCP server (`https://mcp.trackunit.ai/mcp`).
23
+
24
+ - **Configuration:** `.mcp.json` (Claude Code and other clients that read a project `.mcp.json`) and `.cursor/mcp.json` (Cursor).
25
+ - **Authentication:** the user must complete OAuth for the `trackunit` server by signing in with an IrisX account that has the `iris.app.developer` scope. See [Connect Trackunit IrisX MCP](https://help.trackunit.com/en/articles/676615-connect-trackunit-irisx-mcp). In Cursor, open the MCP settings and click Connect on the `trackunit` server; in Claude Code, run `/mcp` and authenticate the `trackunit` server.
26
+
27
+ Before looking up UI or GraphQL information, check whether the `trackunit` server's `explore_*` tools (such as `explore_introspect_gql_schema`) are available, either directly in your tool list or through your client's MCP or tool search/discovery mechanism. Clients may prefix tool names, e.g. `mcp__trackunit__explore_introspect_gql_schema`. A server that is configured but not yet authenticated, or only exposes an authenticate tool, counts as not connected.
28
+
29
+ **If connected**, use the MCP tools:
30
+ - GraphQL schema: `explore_introspect_gql_schema`, and `explore_validate_gql_query` to validate queries
31
+ - Design system: `explore_get_design_system_components`, then `explore_get_design_system_code`
32
+
33
+ **If not connected**, do not block or wait for the user to authenticate; continue with the public sources:
34
+ - Design system: fetch `https://design.iris.trackunit.com/llms.txt`, then `https://design.iris.trackunit.com/ai?storyId=<id>` for the component you need
35
+ - GraphQL schema: find types in the [Developer Hub GraphQL docs](https://developers.trackunit.com/docs/apps-and-extensions/overview/public-apis/graphql-api/) and the [GraphQL Explorer](https://apps.iris.trackunit.com/graphql-public-viewer/), then run the `graphql-hooks` codegen from the `graphql` skill (`.agents/skills/graphql/SKILL.md`). Codegen validates against the public schema, so fix any unknown field or type errors it reports.
36
+
37
+ Never invent components, props, or schema fields; look them up with one of the sources above.
38
+
20
39
  ## IrisX App Commands
21
40
 
22
41
  **ALWAYS use these specific commands** (never generic React/Node.js commands):