nx 22.5.0-beta.0 → 22.5.0-beta.2

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/package.json +14 -13
  2. package/src/ai/clone-ai-config-repo.d.ts +12 -0
  3. package/src/ai/clone-ai-config-repo.d.ts.map +1 -0
  4. package/src/ai/clone-ai-config-repo.js +136 -0
  5. package/src/ai/constants.d.ts +1 -1
  6. package/src/ai/constants.d.ts.map +1 -1
  7. package/src/ai/constants.js +3 -3
  8. package/src/ai/set-up-ai-agents/get-agent-rules.d.ts.map +1 -1
  9. package/src/ai/set-up-ai-agents/get-agent-rules.js +2 -4
  10. package/src/ai/set-up-ai-agents/schema.d.ts +2 -0
  11. package/src/ai/set-up-ai-agents/schema.json +2 -2
  12. package/src/ai/set-up-ai-agents/set-up-ai-agents.d.ts.map +1 -1
  13. package/src/ai/set-up-ai-agents/set-up-ai-agents.js +77 -5
  14. package/src/ai/utils.d.ts +1 -1
  15. package/src/ai/utils.d.ts.map +1 -1
  16. package/src/ai/utils.js +32 -7
  17. package/src/command-line/configure-ai-agents/command-object.js +1 -1
  18. package/src/command-line/import/import.d.ts.map +1 -1
  19. package/src/command-line/import/import.js +9 -1
  20. package/src/command-line/init/command-object.js +1 -1
  21. package/src/command-line/init/init-v2.d.ts +2 -1
  22. package/src/command-line/init/init-v2.d.ts.map +1 -1
  23. package/src/command-line/init/init-v2.js +12 -2
  24. package/src/command-line/release/utils/release-graph.d.ts +1 -1
  25. package/src/core/graph/main.js +1 -1
  26. package/src/core/graph/styles.css +1 -1
  27. package/src/core/graph/styles.js +1 -1
  28. package/src/generators/utils/generate-files.d.ts +45 -0
  29. package/src/generators/utils/generate-files.d.ts.map +1 -0
  30. package/src/generators/utils/generate-files.js +113 -0
  31. package/src/native/index.js +22 -2
  32. package/src/native/nx.wasm32-wasi.wasm +0 -0
  33. package/src/project-graph/error-types.d.ts.map +1 -1
  34. package/src/project-graph/error-types.js +5 -4
  35. package/src/utils/binary-extensions.d.ts +2 -0
  36. package/src/utils/binary-extensions.d.ts.map +1 -0
  37. package/src/utils/binary-extensions.js +279 -0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nx",
3
- "version": "22.5.0-beta.0",
3
+ "version": "22.5.0-beta.2",
4
4
  "private": false,
5
5
  "description": "The core Nx plugin contains the core functionality of Nx like the project graph, nx commands and task orchestration.",
6
6
  "repository": {
@@ -45,6 +45,7 @@
45
45
  "cliui": "^8.0.1",
46
46
  "dotenv": "~16.4.5",
47
47
  "dotenv-expand": "~11.0.6",
48
+ "ejs": "^3.1.7",
48
49
  "enquirer": "~2.3.6",
49
50
  "figures": "3.2.0",
50
51
  "flat": "^5.0.2",
@@ -71,8 +72,8 @@
71
72
  "yargs-parser": "21.1.1"
72
73
  },
73
74
  "peerDependencies": {
74
- "@swc-node/register": "^1.8.0",
75
- "@swc/core": "^1.3.85"
75
+ "@swc-node/register": "^1.11.1",
76
+ "@swc/core": "^1.15.5"
76
77
  },
77
78
  "peerDependenciesMeta": {
78
79
  "@swc-node/register": {
@@ -83,16 +84,16 @@
83
84
  }
84
85
  },
85
86
  "optionalDependencies": {
86
- "@nx/nx-darwin-arm64": "22.5.0-beta.0",
87
- "@nx/nx-darwin-x64": "22.5.0-beta.0",
88
- "@nx/nx-freebsd-x64": "22.5.0-beta.0",
89
- "@nx/nx-linux-arm-gnueabihf": "22.5.0-beta.0",
90
- "@nx/nx-linux-arm64-gnu": "22.5.0-beta.0",
91
- "@nx/nx-linux-arm64-musl": "22.5.0-beta.0",
92
- "@nx/nx-linux-x64-gnu": "22.5.0-beta.0",
93
- "@nx/nx-linux-x64-musl": "22.5.0-beta.0",
94
- "@nx/nx-win32-arm64-msvc": "22.5.0-beta.0",
95
- "@nx/nx-win32-x64-msvc": "22.5.0-beta.0"
87
+ "@nx/nx-darwin-arm64": "22.5.0-beta.2",
88
+ "@nx/nx-darwin-x64": "22.5.0-beta.2",
89
+ "@nx/nx-freebsd-x64": "22.5.0-beta.2",
90
+ "@nx/nx-linux-arm-gnueabihf": "22.5.0-beta.2",
91
+ "@nx/nx-linux-arm64-gnu": "22.5.0-beta.2",
92
+ "@nx/nx-linux-arm64-musl": "22.5.0-beta.2",
93
+ "@nx/nx-linux-x64-gnu": "22.5.0-beta.2",
94
+ "@nx/nx-linux-x64-musl": "22.5.0-beta.2",
95
+ "@nx/nx-win32-arm64-msvc": "22.5.0-beta.2",
96
+ "@nx/nx-win32-x64-msvc": "22.5.0-beta.2"
96
97
  },
97
98
  "nx-migrations": {
98
99
  "migrations": "./migrations.json",
@@ -0,0 +1,12 @@
1
+ /**
2
+ * Get the path to the cached nx-ai-agents-config repository.
3
+ * Uses a commit-hash based caching strategy:
4
+ * 1. Fetches the latest commit hash from the remote repository
5
+ * 2. Checks if a cached version exists for that hash
6
+ * 3. If not, clones the repository and cleans up old caches
7
+ *
8
+ * @returns The path to the cached repository
9
+ * @throws Error if unable to fetch or clone the repository
10
+ */
11
+ export declare function getAiConfigRepoPath(): string;
12
+ //# sourceMappingURL=clone-ai-config-repo.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"clone-ai-config-repo.d.ts","sourceRoot":"","sources":["../../../../../packages/nx/src/ai/clone-ai-config-repo.ts"],"names":[],"mappings":"AAuHA;;;;;;;;;GASG;AACH,wBAAgB,mBAAmB,IAAI,MAAM,CAiB5C"}
@@ -0,0 +1,136 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.getAiConfigRepoPath = getAiConfigRepoPath;
4
+ const child_process_1 = require("child_process");
5
+ const fs_1 = require("fs");
6
+ const os_1 = require("os");
7
+ const path_1 = require("path");
8
+ const REPO_URL = 'https://github.com/nrwl/nx-ai-agents-config';
9
+ const CACHE_DIR = (0, path_1.join)((0, os_1.tmpdir)(), 'nx-ai-agents-config');
10
+ /**
11
+ * Get the latest commit hash from the remote repository.
12
+ * Uses `git ls-remote` to fetch the HEAD commit hash without cloning.
13
+ */
14
+ function getLatestCommitHash() {
15
+ try {
16
+ const output = (0, child_process_1.execSync)(`git ls-remote ${REPO_URL} HEAD`, {
17
+ encoding: 'utf-8',
18
+ stdio: ['pipe', 'pipe', 'pipe'],
19
+ timeout: 30000, // 30 second timeout
20
+ });
21
+ const hash = output.split('\t')[0];
22
+ if (!hash || hash.length < 10) {
23
+ throw new Error('Invalid commit hash received');
24
+ }
25
+ // Return first 10 characters of the commit hash
26
+ return hash.substring(0, 10);
27
+ }
28
+ catch (error) {
29
+ throw new Error(`Failed to fetch latest commit hash from ${REPO_URL}. Please check your network connection.`);
30
+ }
31
+ }
32
+ /**
33
+ * Clone the repository to the specified path using shallow clone.
34
+ */
35
+ function cloneRepo(targetPath) {
36
+ try {
37
+ // Ensure parent directory exists
38
+ (0, fs_1.mkdirSync)(CACHE_DIR, { recursive: true });
39
+ // Use a temporary path first to avoid race conditions
40
+ const tempPath = `${targetPath}.tmp.${process.pid}`;
41
+ // Clean up any leftover temp directory
42
+ if ((0, fs_1.existsSync)(tempPath)) {
43
+ (0, fs_1.rmSync)(tempPath, { recursive: true, force: true });
44
+ }
45
+ (0, child_process_1.execSync)(`git clone --depth 1 ${REPO_URL} "${tempPath}"`, {
46
+ encoding: 'utf-8',
47
+ stdio: ['pipe', 'pipe', 'pipe'],
48
+ timeout: 120000, // 2 minute timeout for clone
49
+ });
50
+ // Remove .git directory after clone
51
+ const gitDir = (0, path_1.join)(tempPath, '.git');
52
+ if ((0, fs_1.existsSync)(gitDir)) {
53
+ (0, fs_1.rmSync)(gitDir, { recursive: true, force: true });
54
+ }
55
+ // Atomically move temp directory to final location
56
+ // If targetPath already exists (race condition), just clean up temp
57
+ if ((0, fs_1.existsSync)(targetPath)) {
58
+ (0, fs_1.rmSync)(tempPath, { recursive: true, force: true });
59
+ }
60
+ else {
61
+ // Rename is atomic on the same filesystem
62
+ try {
63
+ (0, fs_1.renameSync)(tempPath, targetPath);
64
+ }
65
+ catch {
66
+ // Rename failed - check if another process won the race
67
+ if ((0, fs_1.existsSync)(targetPath)) {
68
+ // Another process created it, clean up our temp
69
+ (0, fs_1.rmSync)(tempPath, { recursive: true, force: true });
70
+ }
71
+ else {
72
+ // targetPath still doesn't exist - retry once
73
+ try {
74
+ (0, fs_1.renameSync)(tempPath, targetPath);
75
+ }
76
+ catch (retryError) {
77
+ // Clean up and fail
78
+ (0, fs_1.rmSync)(tempPath, { recursive: true, force: true });
79
+ throw new Error(`Failed to move cloned repository to cache location: ${retryError.message}`);
80
+ }
81
+ }
82
+ }
83
+ }
84
+ }
85
+ catch (error) {
86
+ // Re-throw if it's already our error (from rename failure)
87
+ if (error instanceof Error && error.message.startsWith('Failed to move')) {
88
+ throw error;
89
+ }
90
+ throw new Error(`Failed to clone ${REPO_URL}. Please check your network connection.`);
91
+ }
92
+ }
93
+ /**
94
+ * Clean up old cached versions, keeping only the current one.
95
+ */
96
+ function cleanupOldCaches(currentCommitHash) {
97
+ if (!(0, fs_1.existsSync)(CACHE_DIR)) {
98
+ return;
99
+ }
100
+ try {
101
+ const entries = (0, fs_1.readdirSync)(CACHE_DIR, { withFileTypes: true });
102
+ for (const entry of entries) {
103
+ if (entry.isDirectory() && entry.name !== currentCommitHash) {
104
+ const oldCachePath = (0, path_1.join)(CACHE_DIR, entry.name);
105
+ (0, fs_1.rmSync)(oldCachePath, { recursive: true, force: true });
106
+ }
107
+ }
108
+ }
109
+ catch {
110
+ // Ignore cleanup errors - not critical
111
+ }
112
+ }
113
+ /**
114
+ * Get the path to the cached nx-ai-agents-config repository.
115
+ * Uses a commit-hash based caching strategy:
116
+ * 1. Fetches the latest commit hash from the remote repository
117
+ * 2. Checks if a cached version exists for that hash
118
+ * 3. If not, clones the repository and cleans up old caches
119
+ *
120
+ * @returns The path to the cached repository
121
+ * @throws Error if unable to fetch or clone the repository
122
+ */
123
+ function getAiConfigRepoPath() {
124
+ // 1. Get latest commit hash (first 10 chars)
125
+ const commitHash = getLatestCommitHash();
126
+ // 2. Check if cached version exists
127
+ const cachedPath = (0, path_1.join)(CACHE_DIR, commitHash);
128
+ if ((0, fs_1.existsSync)(cachedPath)) {
129
+ return cachedPath;
130
+ }
131
+ // 3. Clone fresh
132
+ cloneRepo(cachedPath);
133
+ // 4. Clean up old cached versions
134
+ cleanupOldCaches(commitHash);
135
+ return cachedPath;
136
+ }
@@ -3,7 +3,7 @@ export declare function geminiMdPath(root: string): string;
3
3
  export declare function parseGeminiSettings(root: string): any | undefined;
4
4
  export declare function geminiSettingsPath(root: string): string;
5
5
  export declare function claudeMdPath(root: string): string;
6
- export declare function claudeMcpPath(root: string): string;
6
+ export declare function opencodeMcpPath(root: string): string;
7
7
  export declare const codexConfigTomlPath: string;
8
8
  export declare const nxRulesMarkerCommentStart = "<!-- nx configuration start-->";
9
9
  export declare const nxRulesMarkerCommentDescription = "<!-- Leave the start & end comments to automatically receive updates. -->";
@@ -1 +1 @@
1
- {"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../../../../../packages/nx/src/ai/constants.ts"],"names":[],"mappings":"AAMA,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAEjD;AAED,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAEjD;AAED,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,GAAG,GAAG,GAAG,SAAS,CAOjE;AAED,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAEvD;AAED,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAEjD;AAED,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAElD;AAED,eAAO,MAAM,mBAAmB,QAA2C,CAAC;AAE5E,eAAO,MAAM,yBAAyB,mCAAmC,CAAC;AAC1E,eAAO,MAAM,+BAA+B,8EAA8E,CAAC;AAC3H,eAAO,MAAM,uBAAuB,iCAAiC,CAAC;AACtE,eAAO,MAAM,UAAU,QAGtB,CAAC;AAEF,eAAO,MAAM,oBAAoB,GAAI,mBAAmB,OAAO,WAG9D,CAAC;AAEF,eAAO,MAAM,eAAe,6BAA2B,CAAC;AAExD;;;;GAIG;AACH,wBAAgB,kBAAkB,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAQ5D"}
1
+ {"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../../../../../packages/nx/src/ai/constants.ts"],"names":[],"mappings":"AAMA,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAEjD;AAED,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAEjD;AAED,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,GAAG,GAAG,GAAG,SAAS,CAOjE;AAED,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAEvD;AAED,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAEjD;AAED,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAEpD;AAED,eAAO,MAAM,mBAAmB,QAA2C,CAAC;AAE5E,eAAO,MAAM,yBAAyB,mCAAmC,CAAC;AAC1E,eAAO,MAAM,+BAA+B,8EAA8E,CAAC;AAC3H,eAAO,MAAM,uBAAuB,iCAAiC,CAAC;AACtE,eAAO,MAAM,UAAU,QAGtB,CAAC;AAEF,eAAO,MAAM,oBAAoB,GAAI,mBAAmB,OAAO,WAG9D,CAAC;AAEF,eAAO,MAAM,eAAe,6BAA2B,CAAC;AAExD;;;;GAIG;AACH,wBAAgB,kBAAkB,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAQ5D"}
@@ -6,7 +6,7 @@ exports.geminiMdPath = geminiMdPath;
6
6
  exports.parseGeminiSettings = parseGeminiSettings;
7
7
  exports.geminiSettingsPath = geminiSettingsPath;
8
8
  exports.claudeMdPath = claudeMdPath;
9
- exports.claudeMcpPath = claudeMcpPath;
9
+ exports.opencodeMcpPath = opencodeMcpPath;
10
10
  exports.getNxMcpTomlConfig = getNxMcpTomlConfig;
11
11
  const os_1 = require("os");
12
12
  const path_1 = require("path");
@@ -34,8 +34,8 @@ function geminiSettingsPath(root) {
34
34
  function claudeMdPath(root) {
35
35
  return (0, path_1.join)(root, 'CLAUDE.md');
36
36
  }
37
- function claudeMcpPath(root) {
38
- return (0, path_1.join)(root, '.mcp.json');
37
+ function opencodeMcpPath(root) {
38
+ return (0, path_1.join)(root, 'opencode.json');
39
39
  }
40
40
  exports.codexConfigTomlPath = (0, path_1.join)((0, os_1.homedir)(), '.codex', 'config.toml');
41
41
  exports.nxRulesMarkerCommentStart = `<!-- nx configuration start-->`;
@@ -1 +1 @@
1
- {"version":3,"file":"get-agent-rules.d.ts","sourceRoot":"","sources":["../../../../../../packages/nx/src/ai/set-up-ai-agents/get-agent-rules.ts"],"names":[],"mappings":"AAAA,wBAAgB,aAAa,CAAC,OAAO,EAAE,OAAO,UAY7C"}
1
+ {"version":3,"file":"get-agent-rules.d.ts","sourceRoot":"","sources":["../../../../../../packages/nx/src/ai/set-up-ai-agents/get-agent-rules.ts"],"names":[],"mappings":"AAAA,wBAAgB,aAAa,CAAC,OAAO,EAAE,OAAO,UAU7C"}
@@ -7,10 +7,8 @@ function getAgentRules(nxCloud) {
7
7
 
8
8
  - When running tasks (for example build, lint, test, e2e, etc.), always prefer running the task through \`nx\` (i.e. \`nx run\`, \`nx run-many\`, \`nx affected\`) instead of using the underlying tooling directly
9
9
  - You have access to the Nx MCP server and its tools, use them to help the user
10
- - When answering questions about the repository, use the \`nx_workspace\` tool first to gain an understanding of the workspace architecture where applicable.
11
- - When working in individual projects, use the \`nx_project_details\` mcp tool to analyze and understand the specific project structure and dependencies
12
- - For questions around nx configuration, best practices or if you're unsure, use the \`nx_docs\` tool to get relevant, up-to-date docs. Always use this instead of assuming things about nx configuration
13
- - If the user needs help with an Nx configuration or project graph error, use the \`nx_workspace\` tool to get any errors
10
+ - For understanding the workspace structure, projects, or available tasks, use the \`/nx-workspace\` skill which provides guidance on exploring Nx workspaces
11
+ - For questions around nx configuration, best practices or if you're unsure, use the \`nx_docs\` MCP tool to get relevant, up-to-date docs. Always use this instead of assuming things about nx configuration
14
12
  - For Nx plugin best practices, check \`node_modules/@nx/<plugin>/PLUGIN.md\`. Not all plugins have this file - proceed without it if unavailable.
15
13
  `;
16
14
  }
@@ -1,3 +1,5 @@
1
+ import type { Agent } from '../utils';
2
+
1
3
  export type SetupAiAgentsGeneratorSchema = {
2
4
  directory: string;
3
5
  writeNxCloudRules?: boolean;
@@ -25,9 +25,9 @@
25
25
  "description": "The agents to setup Nx configuration for.",
26
26
  "items": {
27
27
  "type": "string",
28
- "enum": ["claude", "gemini", "codex", "cursor", "copilot"]
28
+ "enum": ["claude", "gemini", "codex", "cursor", "copilot", "opencode"]
29
29
  },
30
- "default": ["claude", "gemini", "codex", "cursor", "copilot"]
30
+ "default": ["claude", "gemini", "codex", "cursor", "copilot", "opencode"]
31
31
  }
32
32
  },
33
33
  "required": ["directory"]
@@ -1 +1 @@
1
- {"version":3,"file":"set-up-ai-agents.d.ts","sourceRoot":"","sources":["../../../../../../packages/nx/src/ai/set-up-ai-agents/set-up-ai-agents.ts"],"names":[],"mappings":"AAWA,OAAO,EAAE,IAAI,EAAE,MAAM,uBAAuB,CAAC;AAQ7C,OAAO,EACL,qBAAqB,EACrB,oBAAoB,EACrB,MAAM,oBAAoB,CAAC;AAkB5B,OAAO,EACL,sCAAsC,EACtC,4BAA4B,EAC7B,MAAM,UAAU,CAAC;AAElB,MAAM,MAAM,mBAAmB,GAAG;IAChC,QAAQ,EAAE,oBAAoB,EAAE,CAAC;IACjC,MAAM,EAAE,qBAAqB,EAAE,CAAC;CACjC,CAAC;AAmCF,wBAAsB,sBAAsB,CAC1C,IAAI,EAAE,IAAI,EACV,OAAO,EAAE,4BAA4B,EACrC,KAAK,UAAQ,GACZ,OAAO,CAAC,CAAC,KAAK,CAAC,EAAE,OAAO,KAAK,OAAO,CAAC,mBAAmB,CAAC,CAAC,CAmC5D;AAaD,wBAAsB,0BAA0B,CAC9C,IAAI,EAAE,IAAI,EACV,OAAO,EAAE,sCAAsC,GAC9C,OAAO,CAAC,MAAM,OAAO,CAAC,mBAAmB,CAAC,CAAC,CAwJ7C;AA2DD,eAAe,sBAAsB,CAAC"}
1
+ {"version":3,"file":"set-up-ai-agents.d.ts","sourceRoot":"","sources":["../../../../../../packages/nx/src/ai/set-up-ai-agents/set-up-ai-agents.ts"],"names":[],"mappings":"AAWA,OAAO,EAAE,IAAI,EAAE,MAAM,uBAAuB,CAAC;AAS7C,OAAO,EACL,qBAAqB,EACrB,oBAAoB,EACrB,MAAM,oBAAoB,CAAC;AAwB5B,OAAO,EACL,sCAAsC,EACtC,4BAA4B,EAC7B,MAAM,UAAU,CAAC;AAElB,MAAM,MAAM,mBAAmB,GAAG;IAChC,QAAQ,EAAE,oBAAoB,EAAE,CAAC;IACjC,MAAM,EAAE,qBAAqB,EAAE,CAAC;CACjC,CAAC;AAmCF,wBAAsB,sBAAsB,CAC1C,IAAI,EAAE,IAAI,EACV,OAAO,EAAE,4BAA4B,EACrC,KAAK,UAAQ,GACZ,OAAO,CAAC,CAAC,KAAK,CAAC,EAAE,OAAO,KAAK,OAAO,CAAC,mBAAmB,CAAC,CAAC,CAmC5D;AAaD,wBAAsB,0BAA0B,CAC9C,IAAI,EAAE,IAAI,EACV,OAAO,EAAE,sCAAsC,GAC9C,OAAO,CAAC,MAAM,OAAO,CAAC,mBAAmB,CAAC,CAAC,CAuN7C;AAkFD,eAAe,sBAAsB,CAAC"}
@@ -7,12 +7,14 @@ const os_1 = require("os");
7
7
  const path_1 = require("path");
8
8
  const semver_1 = require("semver");
9
9
  const format_changed_files_with_prettier_if_available_1 = require("../../generators/internal-utils/format-changed-files-with-prettier-if-available");
10
+ const generate_files_1 = require("../../generators/utils/generate-files");
10
11
  const json_1 = require("../../generators/utils/json");
11
12
  const native_1 = require("../../native");
12
13
  const package_json_1 = require("../../utils/package-json");
13
14
  const provenance_1 = require("../../utils/provenance");
14
15
  const workspace_root_1 = require("../../utils/workspace-root");
15
16
  const constants_1 = require("../constants");
17
+ const clone_ai_config_repo_1 = require("../clone-ai-config-repo");
16
18
  const utils_1 = require("../utils");
17
19
  const constants_2 = require("../constants");
18
20
  /**
@@ -76,17 +78,43 @@ async function setupAiAgentsGeneratorImpl(tree, options) {
76
78
  const nxVersion = getNxVersion();
77
79
  const agentsMd = (0, constants_1.agentsMdPath)(options.directory);
78
80
  // write AGENTS.md for most agents
79
- if (hasAgent('cursor') || hasAgent('copilot') || hasAgent('codex')) {
81
+ if (hasAgent('cursor') ||
82
+ hasAgent('copilot') ||
83
+ hasAgent('codex') ||
84
+ hasAgent('opencode')) {
80
85
  writeAgentRules(tree, agentsMd, options.writeNxCloudRules);
81
86
  }
82
87
  if (hasAgent('claude')) {
83
88
  const claudePath = (0, path_1.join)(options.directory, 'CLAUDE.md');
84
89
  writeAgentRules(tree, claudePath, options.writeNxCloudRules);
85
- const mcpJsonPath = (0, path_1.join)(options.directory, '.mcp.json');
86
- if (!tree.exists(mcpJsonPath)) {
87
- (0, json_1.writeJson)(tree, mcpJsonPath, {});
90
+ // Configure Claude plugin via marketplace (plugin includes MCP server)
91
+ const claudeSettingsPath = (0, path_1.join)(options.directory, '.claude', 'settings.json');
92
+ if (!tree.exists(claudeSettingsPath)) {
93
+ (0, json_1.writeJson)(tree, claudeSettingsPath, {});
88
94
  }
89
- (0, json_1.updateJson)(tree, mcpJsonPath, (json) => mcpConfigUpdater(json, nxVersion));
95
+ (0, json_1.updateJson)(tree, claudeSettingsPath, (json) => ({
96
+ ...json,
97
+ extraKnownMarketplaces: {
98
+ ...json.extraKnownMarketplaces,
99
+ 'nx-claude-plugins': {
100
+ source: {
101
+ source: 'github',
102
+ repo: 'nrwl/nx-ai-agents-config',
103
+ },
104
+ },
105
+ },
106
+ enabledPlugins: {
107
+ ...json.enabledPlugins,
108
+ 'nx@nx-claude-plugins': true,
109
+ },
110
+ }));
111
+ }
112
+ if (hasAgent('opencode')) {
113
+ const opencodeMcpJsonPath = (0, constants_1.opencodeMcpPath)(options.directory);
114
+ if (!tree.exists(opencodeMcpJsonPath)) {
115
+ (0, json_1.writeJson)(tree, opencodeMcpJsonPath, {});
116
+ }
117
+ (0, json_1.updateJson)(tree, opencodeMcpJsonPath, (json) => opencodeMcpConfigUpdater(json, nxVersion));
90
118
  }
91
119
  if (hasAgent('gemini')) {
92
120
  const geminiSettingsPath = (0, path_1.join)(options.directory, '.gemini', 'settings.json');
@@ -108,6 +136,29 @@ async function setupAiAgentsGeneratorImpl(tree, options) {
108
136
  writeAgentRules(tree, contextFileName ?? geminiMd, options.writeNxCloudRules);
109
137
  }
110
138
  }
139
+ // Copy extensibility artifacts (commands, skills, subagents) for non-Claude agents
140
+ if (hasAgent('opencode') ||
141
+ hasAgent('copilot') ||
142
+ hasAgent('cursor') ||
143
+ hasAgent('codex') ||
144
+ hasAgent('gemini')) {
145
+ const repoPath = (0, clone_ai_config_repo_1.getAiConfigRepoPath)();
146
+ const agentDirs = [
147
+ { agent: 'opencode', src: 'generated/.opencode', dest: '.opencode' },
148
+ { agent: 'copilot', src: 'generated/.github', dest: '.github' },
149
+ { agent: 'cursor', src: 'generated/.cursor', dest: '.cursor' },
150
+ { agent: 'codex', src: 'generated/.codex', dest: '.codex' },
151
+ { agent: 'gemini', src: 'generated/.gemini', dest: '.gemini' },
152
+ ];
153
+ for (const { agent, src, dest } of agentDirs) {
154
+ if (hasAgent(agent)) {
155
+ const srcPath = (0, path_1.join)(repoPath, src);
156
+ if ((0, fs_1.existsSync)(srcPath)) {
157
+ (0, generate_files_1.generateFiles)(tree, srcPath, (0, path_1.join)(options.directory, dest), {});
158
+ }
159
+ }
160
+ }
161
+ }
111
162
  await (0, format_changed_files_with_prettier_if_available_1.formatChangedFilesWithPrettierIfAvailable)(tree);
112
163
  // we use the check variable to determine if we should actually make changes or just report what would be changed
113
164
  return async (check = false) => {
@@ -244,4 +295,25 @@ function mcpConfigUpdater(existing, nxVersion) {
244
295
  }
245
296
  return existing;
246
297
  }
298
+ function opencodeMcpConfigUpdater(existing, nxVersion) {
299
+ const majorVersion = (0, semver_1.major)(nxVersion);
300
+ const mcpCommand = majorVersion >= 22 ? ['npx', 'nx', 'mcp'] : ['npx', 'nx-mcp'];
301
+ if (existing.mcp) {
302
+ existing.mcp['nx-mcp'] = {
303
+ type: 'local',
304
+ command: mcpCommand,
305
+ enabled: true,
306
+ };
307
+ }
308
+ else {
309
+ existing.mcp = {
310
+ 'nx-mcp': {
311
+ type: 'local',
312
+ command: mcpCommand,
313
+ enabled: true,
314
+ },
315
+ };
316
+ }
317
+ return existing;
318
+ }
247
319
  exports.default = setupAiAgentsGenerator;
package/src/ai/utils.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- export declare const supportedAgents: readonly ["claude", "codex", "copilot", "cursor", "gemini"];
1
+ export declare const supportedAgents: readonly ["claude", "codex", "copilot", "cursor", "gemini", "opencode"];
2
2
  export type Agent = (typeof supportedAgents)[number];
3
3
  export declare const agentDisplayMap: Record<Agent, string>;
4
4
  export type AgentConfiguration = {
@@ -1 +1 @@
1
- {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../../../../packages/nx/src/ai/utils.ts"],"names":[],"mappings":"AA0BA,eAAO,MAAM,eAAe,6DAMlB,CAAC;AACX,MAAM,MAAM,KAAK,GAAG,CAAC,OAAO,eAAe,CAAC,CAAC,MAAM,CAAC,CAAC;AACrD,eAAO,MAAM,eAAe,EAAE,MAAM,CAAC,KAAK,EAAE,MAAM,CAMjD,CAAC;AAEF,MAAM,MAAM,kBAAkB,GAAG;IAC/B,IAAI,EAAE,KAAK,CAAC;IACZ,WAAW,EAAE,MAAM,CAAC;IACpB,KAAK,EAAE,OAAO,CAAC;IACf,GAAG,EAAE,OAAO,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,QAAQ,EAAE,OAAO,CAAC;IAClB,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB,CAAC;AAEF,wBAAsB,sBAAsB,CAC1C,gBAAgB,EAAE,KAAK,EAAE,EACzB,aAAa,EAAE,MAAM,GACpB,OAAO,CAAC;IACT,mBAAmB,EAAE,kBAAkB,EAAE,CAAC;IAC1C,yBAAyB,EAAE,kBAAkB,EAAE,CAAC;IAChD,qBAAqB,EAAE,kBAAkB,EAAE,CAAC;IAC5C,cAAc,EAAE,kBAAkB,EAAE,CAAC;CACtC,CAAC,CA2BD;AAyJD,wBAAsB,eAAe,CACnC,MAAM,EAAE,KAAK,EAAE,EACf,aAAa,EAAE,MAAM,EACrB,SAAS,CAAC,EAAE,OAAO,GAClB,OAAO,CAAC,IAAI,CAAC,CAoBf"}
1
+ {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../../../../packages/nx/src/ai/utils.ts"],"names":[],"mappings":"AA0BA,eAAO,MAAM,eAAe,yEAOlB,CAAC;AACX,MAAM,MAAM,KAAK,GAAG,CAAC,OAAO,eAAe,CAAC,CAAC,MAAM,CAAC,CAAC;AACrD,eAAO,MAAM,eAAe,EAAE,MAAM,CAAC,KAAK,EAAE,MAAM,CAOjD,CAAC;AAEF,MAAM,MAAM,kBAAkB,GAAG;IAC/B,IAAI,EAAE,KAAK,CAAC;IACZ,WAAW,EAAE,MAAM,CAAC;IACpB,KAAK,EAAE,OAAO,CAAC;IACf,GAAG,EAAE,OAAO,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,QAAQ,EAAE,OAAO,CAAC;IAClB,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB,CAAC;AAEF,wBAAsB,sBAAsB,CAC1C,gBAAgB,EAAE,KAAK,EAAE,EACzB,aAAa,EAAE,MAAM,GACpB,OAAO,CAAC;IACT,mBAAmB,EAAE,kBAAkB,EAAE,CAAC;IAC1C,yBAAyB,EAAE,kBAAkB,EAAE,CAAC;IAChD,qBAAqB,EAAE,kBAAkB,EAAE,CAAC;IAC5C,cAAc,EAAE,kBAAkB,EAAE,CAAC;CACtC,CAAC,CA2BD;AAoLD,wBAAsB,eAAe,CACnC,MAAM,EAAE,KAAK,EAAE,EACf,aAAa,EAAE,MAAM,EACrB,SAAS,CAAC,EAAE,OAAO,GAClB,OAAO,CAAC,IAAI,CAAC,CAoBf"}
package/src/ai/utils.js CHANGED
@@ -21,6 +21,7 @@ exports.supportedAgents = [
21
21
  'copilot',
22
22
  'cursor',
23
23
  'gemini',
24
+ 'opencode',
24
25
  ];
25
26
  exports.agentDisplayMap = {
26
27
  claude: 'Claude Code',
@@ -28,6 +29,7 @@ exports.agentDisplayMap = {
28
29
  codex: 'OpenAI Codex',
29
30
  copilot: 'GitHub Copilot for VSCode',
30
31
  cursor: 'Cursor',
32
+ opencode: 'OpenCode',
31
33
  };
32
34
  async function getAgentConfigurations(agentsToConsider, workspaceRoot) {
33
35
  const nonConfiguredAgents = [];
@@ -61,22 +63,24 @@ async function getAgentConfiguration(agent, workspaceRoot) {
61
63
  let agentConfiguration;
62
64
  switch (agent) {
63
65
  case 'claude': {
64
- const mcpPath = (0, constants_1.claudeMcpPath)(workspaceRoot);
65
- let mcpConfigured;
66
+ // Claude uses a plugin from marketplace which includes the MCP server
67
+ const claudeSettingsPath = (0, path_1.resolve)(workspaceRoot, '.claude', 'settings.json');
68
+ let pluginConfigured;
66
69
  try {
67
- const mcpContents = (0, fileutils_1.readJsonFile)(mcpPath);
68
- mcpConfigured = !!mcpContents?.['mcpServers']?.['nx-mcp'];
70
+ const settingsContents = (0, fileutils_1.readJsonFile)(claudeSettingsPath);
71
+ pluginConfigured =
72
+ !!settingsContents?.['enabledPlugins']?.['nx@nx-claude-plugins'];
69
73
  }
70
74
  catch {
71
- mcpConfigured = false;
75
+ pluginConfigured = false;
72
76
  }
73
77
  const rulesPath = (0, constants_1.claudeMdPath)(workspaceRoot);
74
78
  const rulesExists = (0, fs_1.existsSync)(rulesPath);
75
79
  agentConfiguration = {
76
80
  rules: rulesExists,
77
- mcp: mcpConfigured,
81
+ mcp: pluginConfigured,
78
82
  rulesPath: rulesPath,
79
- mcpPath: mcpPath,
83
+ mcpPath: claudeSettingsPath,
80
84
  };
81
85
  break;
82
86
  }
@@ -154,6 +158,27 @@ async function getAgentConfiguration(agent, workspaceRoot) {
154
158
  };
155
159
  break;
156
160
  }
161
+ case 'opencode': {
162
+ const rulesPath = (0, constants_1.agentsMdPath)(workspaceRoot);
163
+ const agentsMdExists = (0, fs_1.existsSync)(rulesPath);
164
+ const mcpPath = (0, constants_1.opencodeMcpPath)(workspaceRoot);
165
+ let mcpConfigured;
166
+ try {
167
+ const mcpContents = (0, fileutils_1.readJsonFile)(mcpPath);
168
+ // OpenCode uses 'mcp' property, not 'mcpServers'
169
+ mcpConfigured = !!mcpContents?.['mcp']?.['nx-mcp'];
170
+ }
171
+ catch {
172
+ mcpConfigured = false;
173
+ }
174
+ agentConfiguration = {
175
+ mcp: mcpConfigured,
176
+ rules: agentsMdExists,
177
+ rulesPath,
178
+ mcpPath,
179
+ };
180
+ break;
181
+ }
157
182
  }
158
183
  return {
159
184
  ...agentConfiguration,
@@ -10,7 +10,7 @@ exports.yargsConfigureAiAgentsCommand = {
10
10
  type: 'array',
11
11
  string: true,
12
12
  description: 'List of AI agents to set up.',
13
- choices: ['claude', 'codex', 'copilot', 'cursor', 'gemini'],
13
+ choices: ['claude', 'codex', 'copilot', 'cursor', 'gemini', 'opencode'],
14
14
  })
15
15
  .option('interactive', {
16
16
  type: 'boolean',
@@ -1 +1 @@
1
- {"version":3,"file":"import.d.ts","sourceRoot":"","sources":["../../../../../../packages/nx/src/command-line/import/import.ts"],"names":[],"mappings":"AAsCA,MAAM,WAAW,aAAa;IAC5B;;OAEG;IACH,gBAAgB,EAAE,MAAM,CAAC;IACzB;;OAEG;IACH,GAAG,EAAE,MAAM,CAAC;IACZ;;OAEG;IACH,MAAM,EAAE,MAAM,CAAC;IACf;;OAEG;IACH,WAAW,EAAE,MAAM,CAAC;IACpB;;OAEG;IACH,KAAK,EAAE,MAAM,CAAC;IAEd,OAAO,EAAE,OAAO,CAAC;IACjB,WAAW,EAAE,OAAO,CAAC;CACtB;AAED,wBAAsB,aAAa,CAAC,OAAO,EAAE,aAAa,iBA4TzD"}
1
+ {"version":3,"file":"import.d.ts","sourceRoot":"","sources":["../../../../../../packages/nx/src/command-line/import/import.ts"],"names":[],"mappings":"AAwCA,MAAM,WAAW,aAAa;IAC5B;;OAEG;IACH,gBAAgB,EAAE,MAAM,CAAC;IACzB;;OAEG;IACH,GAAG,EAAE,MAAM,CAAC;IACZ;;OAEG;IACH,MAAM,EAAE,MAAM,CAAC;IACf;;OAEG;IACH,WAAW,EAAE,MAAM,CAAC;IACpB;;OAEG;IACH,KAAK,EAAE,MAAM,CAAC;IAEd,OAAO,EAAE,OAAO,CAAC;IACjB,WAAW,EAAE,OAAO,CAAC;CACtB;AAED,wBAAsB,aAAa,CAAC,OAAO,EAAE,aAAa,iBAmUzD"}
@@ -12,6 +12,7 @@ const output_1 = require("../../utils/output");
12
12
  const createSpinner = require('ora');
13
13
  const init_v2_1 = require("../init/init-v2");
14
14
  const nx_json_1 = require("../../config/nx-json");
15
+ const fileutils_1 = require("../../utils/fileutils");
15
16
  const workspace_root_1 = require("../../utils/workspace-root");
16
17
  const package_manager_1 = require("../../utils/package-manager");
17
18
  const workspace_context_1 = require("../../utils/workspace-context");
@@ -154,7 +155,14 @@ async function importHandler(options) {
154
155
  const pmc = (0, package_manager_1.getPackageManagerCommand)();
155
156
  const nxJson = (0, nx_json_1.readNxJson)(workspace_root_1.workspaceRoot);
156
157
  (0, workspace_context_1.resetWorkspaceContext)();
157
- const { plugins, updatePackageScripts } = await (0, init_v2_1.detectPlugins)(nxJson, options.interactive, true);
158
+ let packageJson;
159
+ try {
160
+ packageJson = (0, fileutils_1.readJsonFile)('package.json');
161
+ }
162
+ catch {
163
+ packageJson = null;
164
+ }
165
+ const { plugins, updatePackageScripts } = await (0, init_v2_1.detectPlugins)(nxJson, packageJson, options.interactive, true);
158
166
  if (packageManager !== sourcePackageManager) {
159
167
  output_1.output.warn({
160
168
  title: `Mismatched package managers`,
@@ -66,7 +66,7 @@ async function withInitOptions(yargs) {
66
66
  type: 'array',
67
67
  string: true,
68
68
  description: 'List of AI agents to set up.',
69
- choices: ['claude', 'codex', 'copilot', 'cursor', 'gemini'],
69
+ choices: ['claude', 'codex', 'copilot', 'cursor', 'gemini', 'opencode'],
70
70
  });
71
71
  }
72
72
  else {
@@ -1,4 +1,5 @@
1
1
  import { NxJsonConfiguration } from '../../config/nx-json';
2
+ import { PackageJson } from '../../utils/package-json';
2
3
  import { Agent } from '../../ai/utils';
3
4
  export interface InitArgs {
4
5
  interactive: boolean;
@@ -10,7 +11,7 @@ export interface InitArgs {
10
11
  aiAgents?: Agent[];
11
12
  }
12
13
  export declare function initHandler(options: InitArgs, inner?: boolean): Promise<void>;
13
- export declare function detectPlugins(nxJson: NxJsonConfiguration, interactive: boolean, includeAngularCli?: boolean): Promise<{
14
+ export declare function detectPlugins(nxJson: NxJsonConfiguration, packageJson: PackageJson | null, interactive: boolean, includeAngularCli?: boolean): Promise<{
14
15
  plugins: string[];
15
16
  updatePackageScripts: boolean;
16
17
  }>;
@@ -1 +1 @@
1
- {"version":3,"file":"init-v2.d.ts","sourceRoot":"","sources":["../../../../../../packages/nx/src/command-line/init/init-v2.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,mBAAmB,EAAc,MAAM,sBAAsB,CAAC;AAavE,OAAO,EAAE,KAAK,EAAE,MAAM,gBAAgB,CAAC;AAkBvC,MAAM,WAAW,QAAQ;IACvB,WAAW,EAAE,OAAO,CAAC;IACrB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,oBAAoB,CAAC,EAAE,OAAO,CAAC;IAC/B,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,QAAQ,CAAC,EAAE,KAAK,EAAE,CAAC;CACpB;AAED,wBAAsB,WAAW,CAC/B,OAAO,EAAE,QAAQ,EACjB,KAAK,UAAQ,GACZ,OAAO,CAAC,IAAI,CAAC,CA2Bf;AAsMD,wBAAsB,aAAa,CACjC,MAAM,EAAE,mBAAmB,EAC3B,WAAW,EAAE,OAAO,EACpB,iBAAiB,CAAC,EAAE,OAAO,GAC1B,OAAO,CAAC;IACT,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,oBAAoB,EAAE,OAAO,CAAC;CAC/B,CAAC,CA2JD"}
1
+ {"version":3,"file":"init-v2.d.ts","sourceRoot":"","sources":["../../../../../../packages/nx/src/command-line/init/init-v2.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,mBAAmB,EAAc,MAAM,sBAAsB,CAAC;AAIvE,OAAO,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AASvD,OAAO,EAAE,KAAK,EAAE,MAAM,gBAAgB,CAAC;AAkBvC,MAAM,WAAW,QAAQ;IACvB,WAAW,EAAE,OAAO,CAAC;IACrB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,oBAAoB,CAAC,EAAE,OAAO,CAAC;IAC/B,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,QAAQ,CAAC,EAAE,KAAK,EAAE,CAAC;CACpB;AAED,wBAAsB,WAAW,CAC/B,OAAO,EAAE,QAAQ,EACjB,KAAK,UAAQ,GACZ,OAAO,CAAC,IAAI,CAAC,CA2Bf;AAsMD,wBAAsB,aAAa,CACjC,MAAM,EAAE,mBAAmB,EAC3B,WAAW,EAAE,WAAW,GAAG,IAAI,EAC/B,WAAW,EAAE,OAAO,EACpB,iBAAiB,CAAC,EAAE,OAAO,GAC1B,OAAO,CAAC;IACT,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,oBAAoB,EAAE,OAAO,CAAC;CAC/B,CAAC,CAsKD"}
@@ -143,7 +143,7 @@ async function initHandlerImpl(options) {
143
143
  updatePackageScripts = true;
144
144
  }
145
145
  else {
146
- const { plugins: _plugins, updatePackageScripts: _updatePackageScripts } = await detectPlugins(nxJson, options.interactive);
146
+ const { plugins: _plugins, updatePackageScripts: _updatePackageScripts } = await detectPlugins(nxJson, packageJson, options.interactive);
147
147
  plugins = _plugins;
148
148
  updatePackageScripts = _updatePackageScripts;
149
149
  }
@@ -212,12 +212,22 @@ const npmPackageToPluginMap = {
212
212
  '@rsbuild/core': '@nx/rsbuild',
213
213
  '@react-router/dev': '@nx/react',
214
214
  };
215
- async function detectPlugins(nxJson, interactive, includeAngularCli) {
215
+ async function detectPlugins(nxJson, packageJson, interactive, includeAngularCli) {
216
216
  let files = ['package.json'].concat((0, workspace_context_1.globWithWorkspaceContextSync)(process.cwd(), ['**/*/package.json']));
217
217
  const currentPlugins = new Set((nxJson.plugins ?? []).map((p) => {
218
218
  const plugin = typeof p === 'string' ? p : p.plugin;
219
219
  return (0, get_package_name_from_import_path_1.getPackageNameFromImportPath)(plugin);
220
220
  }));
221
+ // Also treat already-installed @nx/* and @nrwl/* packages as current plugins
222
+ const rootDeps = {
223
+ ...packageJson?.dependencies,
224
+ ...packageJson?.devDependencies,
225
+ };
226
+ for (const dep of Object.keys(rootDeps)) {
227
+ if (dep.startsWith('@nx/') || dep.startsWith('@nrwl/')) {
228
+ currentPlugins.add((0, get_package_name_from_import_path_1.getPackageNameFromImportPath)(dep));
229
+ }
230
+ }
221
231
  const detectedPlugins = new Set();
222
232
  for (const file of files) {
223
233
  if (!(0, fs_1.existsSync)(file))
@@ -63,7 +63,7 @@ export declare class ReleaseGraph {
63
63
  readonly projectToReleaseGroup: Map<string, ReleaseGroupWithName>;
64
64
  readonly projectToDependents: Map<string, Set<string>>;
65
65
  readonly projectToDependencies: Map<string, Set<string>>;
66
- readonly projectToUpdateDependentsSetting: Map<string, "never" | "auto" | "always">;
66
+ readonly projectToUpdateDependentsSetting: Map<string, "auto" | "always" | "never">;
67
67
  readonly groupGraph: Map<string, GroupNode>;
68
68
  sortedReleaseGroups: string[];
69
69
  readonly sortedProjects: Map<string, string[]>;