cc4pm 1.8.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/.claude-plugin/README.md +17 -0
- package/.claude-plugin/plugin.json +25 -0
- package/LICENSE +21 -0
- package/README.md +157 -0
- package/README.zh-CN.md +134 -0
- package/contexts/dev.md +20 -0
- package/contexts/research.md +26 -0
- package/contexts/review.md +22 -0
- package/examples/CLAUDE.md +100 -0
- package/examples/statusline.json +19 -0
- package/examples/user-CLAUDE.md +109 -0
- package/install.sh +17 -0
- package/manifests/install-components.json +173 -0
- package/manifests/install-modules.json +335 -0
- package/manifests/install-profiles.json +75 -0
- package/package.json +117 -0
- package/schemas/ecc-install-config.schema.json +58 -0
- package/schemas/hooks.schema.json +197 -0
- package/schemas/install-components.schema.json +56 -0
- package/schemas/install-modules.schema.json +105 -0
- package/schemas/install-profiles.schema.json +45 -0
- package/schemas/install-state.schema.json +210 -0
- package/schemas/package-manager.schema.json +23 -0
- package/schemas/plugin.schema.json +58 -0
- package/scripts/ci/catalog.js +83 -0
- package/scripts/ci/validate-agents.js +81 -0
- package/scripts/ci/validate-commands.js +135 -0
- package/scripts/ci/validate-hooks.js +239 -0
- package/scripts/ci/validate-install-manifests.js +211 -0
- package/scripts/ci/validate-no-personal-paths.js +63 -0
- package/scripts/ci/validate-rules.js +81 -0
- package/scripts/ci/validate-skills.js +54 -0
- package/scripts/claw.js +468 -0
- package/scripts/doctor.js +110 -0
- package/scripts/ecc.js +194 -0
- package/scripts/hooks/auto-tmux-dev.js +88 -0
- package/scripts/hooks/check-console-log.js +71 -0
- package/scripts/hooks/check-hook-enabled.js +12 -0
- package/scripts/hooks/cost-tracker.js +78 -0
- package/scripts/hooks/doc-file-warning.js +63 -0
- package/scripts/hooks/evaluate-session.js +100 -0
- package/scripts/hooks/insaits-security-monitor.py +269 -0
- package/scripts/hooks/insaits-security-wrapper.js +88 -0
- package/scripts/hooks/post-bash-build-complete.js +27 -0
- package/scripts/hooks/post-bash-pr-created.js +36 -0
- package/scripts/hooks/post-edit-console-warn.js +54 -0
- package/scripts/hooks/post-edit-format.js +109 -0
- package/scripts/hooks/post-edit-typecheck.js +96 -0
- package/scripts/hooks/pre-bash-dev-server-block.js +187 -0
- package/scripts/hooks/pre-bash-git-push-reminder.js +28 -0
- package/scripts/hooks/pre-bash-tmux-reminder.js +33 -0
- package/scripts/hooks/pre-compact.js +48 -0
- package/scripts/hooks/pre-write-doc-warn.js +9 -0
- package/scripts/hooks/quality-gate.js +168 -0
- package/scripts/hooks/run-with-flags-shell.sh +32 -0
- package/scripts/hooks/run-with-flags.js +120 -0
- package/scripts/hooks/session-end-marker.js +15 -0
- package/scripts/hooks/session-end.js +299 -0
- package/scripts/hooks/session-start.js +97 -0
- package/scripts/hooks/suggest-compact.js +80 -0
- package/scripts/install-apply.js +137 -0
- package/scripts/install-plan.js +254 -0
- package/scripts/lib/hook-flags.js +74 -0
- package/scripts/lib/install/apply.js +23 -0
- package/scripts/lib/install/config.js +82 -0
- package/scripts/lib/install/request.js +113 -0
- package/scripts/lib/install/runtime.js +42 -0
- package/scripts/lib/install-executor.js +605 -0
- package/scripts/lib/install-lifecycle.js +763 -0
- package/scripts/lib/install-manifests.js +305 -0
- package/scripts/lib/install-state.js +120 -0
- package/scripts/lib/install-targets/antigravity-project.js +9 -0
- package/scripts/lib/install-targets/claude-home.js +10 -0
- package/scripts/lib/install-targets/codex-home.js +10 -0
- package/scripts/lib/install-targets/cursor-project.js +10 -0
- package/scripts/lib/install-targets/helpers.js +89 -0
- package/scripts/lib/install-targets/opencode-home.js +10 -0
- package/scripts/lib/install-targets/registry.js +64 -0
- package/scripts/lib/orchestration-session.js +299 -0
- package/scripts/lib/package-manager.d.ts +119 -0
- package/scripts/lib/package-manager.js +431 -0
- package/scripts/lib/project-detect.js +428 -0
- package/scripts/lib/resolve-formatter.js +185 -0
- package/scripts/lib/session-adapters/canonical-session.js +138 -0
- package/scripts/lib/session-adapters/claude-history.js +149 -0
- package/scripts/lib/session-adapters/dmux-tmux.js +80 -0
- package/scripts/lib/session-adapters/registry.js +111 -0
- package/scripts/lib/session-aliases.d.ts +136 -0
- package/scripts/lib/session-aliases.js +481 -0
- package/scripts/lib/session-manager.d.ts +131 -0
- package/scripts/lib/session-manager.js +464 -0
- package/scripts/lib/shell-split.js +86 -0
- package/scripts/lib/skill-improvement/amendify.js +89 -0
- package/scripts/lib/skill-improvement/evaluate.js +59 -0
- package/scripts/lib/skill-improvement/health.js +118 -0
- package/scripts/lib/skill-improvement/observations.js +108 -0
- package/scripts/lib/tmux-worktree-orchestrator.js +491 -0
- package/scripts/lib/utils.d.ts +183 -0
- package/scripts/lib/utils.js +543 -0
- package/scripts/list-installed.js +90 -0
- package/scripts/orchestrate-codex-worker.sh +92 -0
- package/scripts/orchestrate-worktrees.js +108 -0
- package/scripts/orchestration-status.js +62 -0
- package/scripts/repair.js +97 -0
- package/scripts/session-inspect.js +150 -0
- package/scripts/setup-package-manager.js +204 -0
- package/scripts/skill-create-output.js +244 -0
- package/scripts/uninstall.js +96 -0
|
@@ -0,0 +1,605 @@
|
|
|
1
|
+
const fs = require('fs');
|
|
2
|
+
const path = require('path');
|
|
3
|
+
const { execFileSync } = require('child_process');
|
|
4
|
+
|
|
5
|
+
const { applyInstallPlan } = require('./install/apply');
|
|
6
|
+
const { LEGACY_INSTALL_TARGETS, parseInstallArgs } = require('./install/request');
|
|
7
|
+
const {
|
|
8
|
+
SUPPORTED_INSTALL_TARGETS,
|
|
9
|
+
resolveInstallPlan,
|
|
10
|
+
} = require('./install-manifests');
|
|
11
|
+
const { getInstallTargetAdapter } = require('./install-targets/registry');
|
|
12
|
+
const { createInstallState } = require('./install-state');
|
|
13
|
+
|
|
14
|
+
const LANGUAGE_NAME_PATTERN = /^[a-zA-Z0-9_-]+$/;
|
|
15
|
+
const EXCLUDED_GENERATED_SOURCE_SUFFIXES = [
|
|
16
|
+
'/ecc-install-state.json',
|
|
17
|
+
'/ecc/install-state.json',
|
|
18
|
+
];
|
|
19
|
+
|
|
20
|
+
function getSourceRoot() {
|
|
21
|
+
return path.join(__dirname, '../..');
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
function getPackageVersion(sourceRoot) {
|
|
25
|
+
try {
|
|
26
|
+
const packageJson = JSON.parse(
|
|
27
|
+
fs.readFileSync(path.join(sourceRoot, 'package.json'), 'utf8')
|
|
28
|
+
);
|
|
29
|
+
return packageJson.version || null;
|
|
30
|
+
} catch (_error) {
|
|
31
|
+
return null;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
function getManifestVersion(sourceRoot) {
|
|
36
|
+
try {
|
|
37
|
+
const modulesManifest = JSON.parse(
|
|
38
|
+
fs.readFileSync(path.join(sourceRoot, 'manifests', 'install-modules.json'), 'utf8')
|
|
39
|
+
);
|
|
40
|
+
return modulesManifest.version || 1;
|
|
41
|
+
} catch (_error) {
|
|
42
|
+
return 1;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
function getRepoCommit(sourceRoot) {
|
|
47
|
+
try {
|
|
48
|
+
return execFileSync('git', ['rev-parse', 'HEAD'], {
|
|
49
|
+
cwd: sourceRoot,
|
|
50
|
+
encoding: 'utf8',
|
|
51
|
+
stdio: ['ignore', 'pipe', 'ignore'],
|
|
52
|
+
timeout: 5000,
|
|
53
|
+
}).trim();
|
|
54
|
+
} catch (_error) {
|
|
55
|
+
return null;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
function readDirectoryNames(dirPath) {
|
|
60
|
+
if (!fs.existsSync(dirPath)) {
|
|
61
|
+
return [];
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
return fs.readdirSync(dirPath, { withFileTypes: true })
|
|
65
|
+
.filter(entry => entry.isDirectory())
|
|
66
|
+
.map(entry => entry.name)
|
|
67
|
+
.sort();
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
function listAvailableLanguages(sourceRoot = getSourceRoot()) {
|
|
71
|
+
return readDirectoryNames(path.join(sourceRoot, 'rules'))
|
|
72
|
+
.filter(name => name !== 'common');
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
function validateLegacyTarget(target) {
|
|
76
|
+
if (!LEGACY_INSTALL_TARGETS.includes(target)) {
|
|
77
|
+
throw new Error(
|
|
78
|
+
`Unknown install target: ${target}. Expected one of ${LEGACY_INSTALL_TARGETS.join(', ')}`
|
|
79
|
+
);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
function listFilesRecursive(dirPath) {
|
|
84
|
+
if (!fs.existsSync(dirPath)) {
|
|
85
|
+
return [];
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
const files = [];
|
|
89
|
+
const entries = fs.readdirSync(dirPath, { withFileTypes: true });
|
|
90
|
+
|
|
91
|
+
for (const entry of entries) {
|
|
92
|
+
const absolutePath = path.join(dirPath, entry.name);
|
|
93
|
+
if (entry.isDirectory()) {
|
|
94
|
+
const childFiles = listFilesRecursive(absolutePath);
|
|
95
|
+
for (const childFile of childFiles) {
|
|
96
|
+
files.push(path.join(entry.name, childFile));
|
|
97
|
+
}
|
|
98
|
+
} else if (entry.isFile()) {
|
|
99
|
+
files.push(entry.name);
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
return files.sort();
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
function isGeneratedRuntimeSourcePath(sourceRelativePath) {
|
|
107
|
+
const normalizedPath = String(sourceRelativePath || '').replace(/\\/g, '/');
|
|
108
|
+
return EXCLUDED_GENERATED_SOURCE_SUFFIXES.some(suffix => normalizedPath.endsWith(suffix));
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
function buildCopyFileOperation({ moduleId, sourcePath, sourceRelativePath, destinationPath, strategy }) {
|
|
112
|
+
return {
|
|
113
|
+
kind: 'copy-file',
|
|
114
|
+
moduleId,
|
|
115
|
+
sourcePath,
|
|
116
|
+
sourceRelativePath,
|
|
117
|
+
destinationPath,
|
|
118
|
+
strategy,
|
|
119
|
+
ownership: 'managed',
|
|
120
|
+
scaffoldOnly: false,
|
|
121
|
+
};
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
function addRecursiveCopyOperations(operations, options) {
|
|
125
|
+
const sourceDir = path.join(options.sourceRoot, options.sourceRelativeDir);
|
|
126
|
+
if (!fs.existsSync(sourceDir)) {
|
|
127
|
+
return 0;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
const relativeFiles = listFilesRecursive(sourceDir);
|
|
131
|
+
|
|
132
|
+
for (const relativeFile of relativeFiles) {
|
|
133
|
+
const sourceRelativePath = path.join(options.sourceRelativeDir, relativeFile);
|
|
134
|
+
const sourcePath = path.join(options.sourceRoot, sourceRelativePath);
|
|
135
|
+
const destinationPath = path.join(options.destinationDir, relativeFile);
|
|
136
|
+
operations.push(buildCopyFileOperation({
|
|
137
|
+
moduleId: options.moduleId,
|
|
138
|
+
sourcePath,
|
|
139
|
+
sourceRelativePath,
|
|
140
|
+
destinationPath,
|
|
141
|
+
strategy: options.strategy || 'preserve-relative-path',
|
|
142
|
+
}));
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
return relativeFiles.length;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
function addFileCopyOperation(operations, options) {
|
|
149
|
+
const sourcePath = path.join(options.sourceRoot, options.sourceRelativePath);
|
|
150
|
+
if (!fs.existsSync(sourcePath)) {
|
|
151
|
+
return false;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
operations.push(buildCopyFileOperation({
|
|
155
|
+
moduleId: options.moduleId,
|
|
156
|
+
sourcePath,
|
|
157
|
+
sourceRelativePath: options.sourceRelativePath,
|
|
158
|
+
destinationPath: options.destinationPath,
|
|
159
|
+
strategy: options.strategy || 'preserve-relative-path',
|
|
160
|
+
}));
|
|
161
|
+
|
|
162
|
+
return true;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
function addMatchingRuleOperations(operations, options) {
|
|
166
|
+
const sourceDir = path.join(options.sourceRoot, options.sourceRelativeDir);
|
|
167
|
+
if (!fs.existsSync(sourceDir)) {
|
|
168
|
+
return 0;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
const files = fs.readdirSync(sourceDir, { withFileTypes: true })
|
|
172
|
+
.filter(entry => entry.isFile() && options.matcher(entry.name))
|
|
173
|
+
.map(entry => entry.name)
|
|
174
|
+
.sort();
|
|
175
|
+
|
|
176
|
+
for (const fileName of files) {
|
|
177
|
+
const sourceRelativePath = path.join(options.sourceRelativeDir, fileName);
|
|
178
|
+
const sourcePath = path.join(options.sourceRoot, sourceRelativePath);
|
|
179
|
+
const destinationPath = path.join(
|
|
180
|
+
options.destinationDir,
|
|
181
|
+
options.rename ? options.rename(fileName) : fileName
|
|
182
|
+
);
|
|
183
|
+
|
|
184
|
+
operations.push(buildCopyFileOperation({
|
|
185
|
+
moduleId: options.moduleId,
|
|
186
|
+
sourcePath,
|
|
187
|
+
sourceRelativePath,
|
|
188
|
+
destinationPath,
|
|
189
|
+
strategy: options.strategy || 'flatten-copy',
|
|
190
|
+
}));
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
return files.length;
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
function isDirectoryNonEmpty(dirPath) {
|
|
197
|
+
return fs.existsSync(dirPath) && fs.statSync(dirPath).isDirectory() && fs.readdirSync(dirPath).length > 0;
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
function planClaudeLegacyInstall(context) {
|
|
201
|
+
const adapter = getInstallTargetAdapter('claude');
|
|
202
|
+
const targetRoot = adapter.resolveRoot({ homeDir: context.homeDir });
|
|
203
|
+
const rulesDir = context.claudeRulesDir || path.join(targetRoot, 'rules');
|
|
204
|
+
const installStatePath = adapter.getInstallStatePath({ homeDir: context.homeDir });
|
|
205
|
+
const operations = [];
|
|
206
|
+
const warnings = [];
|
|
207
|
+
|
|
208
|
+
if (isDirectoryNonEmpty(rulesDir)) {
|
|
209
|
+
warnings.push(
|
|
210
|
+
`Destination ${rulesDir}/ already exists and files may be overwritten`
|
|
211
|
+
);
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
addRecursiveCopyOperations(operations, {
|
|
215
|
+
moduleId: 'legacy-claude-rules',
|
|
216
|
+
sourceRoot: context.sourceRoot,
|
|
217
|
+
sourceRelativeDir: path.join('rules', 'common'),
|
|
218
|
+
destinationDir: path.join(rulesDir, 'common'),
|
|
219
|
+
});
|
|
220
|
+
|
|
221
|
+
for (const language of context.languages) {
|
|
222
|
+
if (!LANGUAGE_NAME_PATTERN.test(language)) {
|
|
223
|
+
warnings.push(
|
|
224
|
+
`Invalid language name '${language}'. Only alphanumeric, dash, and underscore are allowed`
|
|
225
|
+
);
|
|
226
|
+
continue;
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
const sourceDir = path.join(context.sourceRoot, 'rules', language);
|
|
230
|
+
if (!fs.existsSync(sourceDir)) {
|
|
231
|
+
warnings.push(`rules/${language}/ does not exist, skipping`);
|
|
232
|
+
continue;
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
addRecursiveCopyOperations(operations, {
|
|
236
|
+
moduleId: 'legacy-claude-rules',
|
|
237
|
+
sourceRoot: context.sourceRoot,
|
|
238
|
+
sourceRelativeDir: path.join('rules', language),
|
|
239
|
+
destinationDir: path.join(rulesDir, language),
|
|
240
|
+
});
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
return {
|
|
244
|
+
mode: 'legacy',
|
|
245
|
+
adapter,
|
|
246
|
+
target: 'claude',
|
|
247
|
+
targetRoot,
|
|
248
|
+
installRoot: rulesDir,
|
|
249
|
+
installStatePath,
|
|
250
|
+
operations,
|
|
251
|
+
warnings,
|
|
252
|
+
selectedModules: ['legacy-claude-rules'],
|
|
253
|
+
};
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
function planCursorLegacyInstall(context) {
|
|
257
|
+
const adapter = getInstallTargetAdapter('cursor');
|
|
258
|
+
const targetRoot = adapter.resolveRoot({ repoRoot: context.projectRoot });
|
|
259
|
+
const installStatePath = adapter.getInstallStatePath({ repoRoot: context.projectRoot });
|
|
260
|
+
const operations = [];
|
|
261
|
+
const warnings = [];
|
|
262
|
+
|
|
263
|
+
addMatchingRuleOperations(operations, {
|
|
264
|
+
moduleId: 'legacy-cursor-install',
|
|
265
|
+
sourceRoot: context.sourceRoot,
|
|
266
|
+
sourceRelativeDir: path.join('.cursor', 'rules'),
|
|
267
|
+
destinationDir: path.join(targetRoot, 'rules'),
|
|
268
|
+
matcher: fileName => /^common-.*\.md$/.test(fileName),
|
|
269
|
+
});
|
|
270
|
+
|
|
271
|
+
for (const language of context.languages) {
|
|
272
|
+
if (!LANGUAGE_NAME_PATTERN.test(language)) {
|
|
273
|
+
warnings.push(
|
|
274
|
+
`Invalid language name '${language}'. Only alphanumeric, dash, and underscore are allowed`
|
|
275
|
+
);
|
|
276
|
+
continue;
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
const matches = addMatchingRuleOperations(operations, {
|
|
280
|
+
moduleId: 'legacy-cursor-install',
|
|
281
|
+
sourceRoot: context.sourceRoot,
|
|
282
|
+
sourceRelativeDir: path.join('.cursor', 'rules'),
|
|
283
|
+
destinationDir: path.join(targetRoot, 'rules'),
|
|
284
|
+
matcher: fileName => fileName.startsWith(`${language}-`) && fileName.endsWith('.md'),
|
|
285
|
+
});
|
|
286
|
+
|
|
287
|
+
if (matches === 0) {
|
|
288
|
+
warnings.push(`No Cursor rules for '${language}' found, skipping`);
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
addRecursiveCopyOperations(operations, {
|
|
293
|
+
moduleId: 'legacy-cursor-install',
|
|
294
|
+
sourceRoot: context.sourceRoot,
|
|
295
|
+
sourceRelativeDir: path.join('.cursor', 'agents'),
|
|
296
|
+
destinationDir: path.join(targetRoot, 'agents'),
|
|
297
|
+
});
|
|
298
|
+
addRecursiveCopyOperations(operations, {
|
|
299
|
+
moduleId: 'legacy-cursor-install',
|
|
300
|
+
sourceRoot: context.sourceRoot,
|
|
301
|
+
sourceRelativeDir: path.join('.cursor', 'skills'),
|
|
302
|
+
destinationDir: path.join(targetRoot, 'skills'),
|
|
303
|
+
});
|
|
304
|
+
addRecursiveCopyOperations(operations, {
|
|
305
|
+
moduleId: 'legacy-cursor-install',
|
|
306
|
+
sourceRoot: context.sourceRoot,
|
|
307
|
+
sourceRelativeDir: path.join('.cursor', 'commands'),
|
|
308
|
+
destinationDir: path.join(targetRoot, 'commands'),
|
|
309
|
+
});
|
|
310
|
+
addRecursiveCopyOperations(operations, {
|
|
311
|
+
moduleId: 'legacy-cursor-install',
|
|
312
|
+
sourceRoot: context.sourceRoot,
|
|
313
|
+
sourceRelativeDir: path.join('.cursor', 'hooks'),
|
|
314
|
+
destinationDir: path.join(targetRoot, 'hooks'),
|
|
315
|
+
});
|
|
316
|
+
|
|
317
|
+
addFileCopyOperation(operations, {
|
|
318
|
+
moduleId: 'legacy-cursor-install',
|
|
319
|
+
sourceRoot: context.sourceRoot,
|
|
320
|
+
sourceRelativePath: path.join('.cursor', 'hooks.json'),
|
|
321
|
+
destinationPath: path.join(targetRoot, 'hooks.json'),
|
|
322
|
+
});
|
|
323
|
+
addFileCopyOperation(operations, {
|
|
324
|
+
moduleId: 'legacy-cursor-install',
|
|
325
|
+
sourceRoot: context.sourceRoot,
|
|
326
|
+
sourceRelativePath: path.join('.cursor', 'mcp.json'),
|
|
327
|
+
destinationPath: path.join(targetRoot, 'mcp.json'),
|
|
328
|
+
});
|
|
329
|
+
|
|
330
|
+
return {
|
|
331
|
+
mode: 'legacy',
|
|
332
|
+
adapter,
|
|
333
|
+
target: 'cursor',
|
|
334
|
+
targetRoot,
|
|
335
|
+
installRoot: targetRoot,
|
|
336
|
+
installStatePath,
|
|
337
|
+
operations,
|
|
338
|
+
warnings,
|
|
339
|
+
selectedModules: ['legacy-cursor-install'],
|
|
340
|
+
};
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
function planAntigravityLegacyInstall(context) {
|
|
344
|
+
const adapter = getInstallTargetAdapter('antigravity');
|
|
345
|
+
const targetRoot = adapter.resolveRoot({ repoRoot: context.projectRoot });
|
|
346
|
+
const installStatePath = adapter.getInstallStatePath({ repoRoot: context.projectRoot });
|
|
347
|
+
const operations = [];
|
|
348
|
+
const warnings = [];
|
|
349
|
+
|
|
350
|
+
if (isDirectoryNonEmpty(path.join(targetRoot, 'rules'))) {
|
|
351
|
+
warnings.push(
|
|
352
|
+
`Destination ${path.join(targetRoot, 'rules')}/ already exists and files may be overwritten`
|
|
353
|
+
);
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
addMatchingRuleOperations(operations, {
|
|
357
|
+
moduleId: 'legacy-antigravity-install',
|
|
358
|
+
sourceRoot: context.sourceRoot,
|
|
359
|
+
sourceRelativeDir: path.join('rules', 'common'),
|
|
360
|
+
destinationDir: path.join(targetRoot, 'rules'),
|
|
361
|
+
matcher: fileName => fileName.endsWith('.md'),
|
|
362
|
+
rename: fileName => `common-${fileName}`,
|
|
363
|
+
});
|
|
364
|
+
|
|
365
|
+
for (const language of context.languages) {
|
|
366
|
+
if (!LANGUAGE_NAME_PATTERN.test(language)) {
|
|
367
|
+
warnings.push(
|
|
368
|
+
`Invalid language name '${language}'. Only alphanumeric, dash, and underscore are allowed`
|
|
369
|
+
);
|
|
370
|
+
continue;
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
const sourceDir = path.join(context.sourceRoot, 'rules', language);
|
|
374
|
+
if (!fs.existsSync(sourceDir)) {
|
|
375
|
+
warnings.push(`rules/${language}/ does not exist, skipping`);
|
|
376
|
+
continue;
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
addMatchingRuleOperations(operations, {
|
|
380
|
+
moduleId: 'legacy-antigravity-install',
|
|
381
|
+
sourceRoot: context.sourceRoot,
|
|
382
|
+
sourceRelativeDir: path.join('rules', language),
|
|
383
|
+
destinationDir: path.join(targetRoot, 'rules'),
|
|
384
|
+
matcher: fileName => fileName.endsWith('.md'),
|
|
385
|
+
rename: fileName => `${language}-${fileName}`,
|
|
386
|
+
});
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
addRecursiveCopyOperations(operations, {
|
|
390
|
+
moduleId: 'legacy-antigravity-install',
|
|
391
|
+
sourceRoot: context.sourceRoot,
|
|
392
|
+
sourceRelativeDir: 'commands',
|
|
393
|
+
destinationDir: path.join(targetRoot, 'workflows'),
|
|
394
|
+
});
|
|
395
|
+
addRecursiveCopyOperations(operations, {
|
|
396
|
+
moduleId: 'legacy-antigravity-install',
|
|
397
|
+
sourceRoot: context.sourceRoot,
|
|
398
|
+
sourceRelativeDir: 'agents',
|
|
399
|
+
destinationDir: path.join(targetRoot, 'skills'),
|
|
400
|
+
});
|
|
401
|
+
addRecursiveCopyOperations(operations, {
|
|
402
|
+
moduleId: 'legacy-antigravity-install',
|
|
403
|
+
sourceRoot: context.sourceRoot,
|
|
404
|
+
sourceRelativeDir: 'skills',
|
|
405
|
+
destinationDir: path.join(targetRoot, 'skills'),
|
|
406
|
+
});
|
|
407
|
+
|
|
408
|
+
return {
|
|
409
|
+
mode: 'legacy',
|
|
410
|
+
adapter,
|
|
411
|
+
target: 'antigravity',
|
|
412
|
+
targetRoot,
|
|
413
|
+
installRoot: targetRoot,
|
|
414
|
+
installStatePath,
|
|
415
|
+
operations,
|
|
416
|
+
warnings,
|
|
417
|
+
selectedModules: ['legacy-antigravity-install'],
|
|
418
|
+
};
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
function createLegacyInstallPlan(options = {}) {
|
|
422
|
+
const sourceRoot = options.sourceRoot || getSourceRoot();
|
|
423
|
+
const projectRoot = options.projectRoot || process.cwd();
|
|
424
|
+
const homeDir = options.homeDir || process.env.HOME;
|
|
425
|
+
const target = options.target || 'claude';
|
|
426
|
+
|
|
427
|
+
validateLegacyTarget(target);
|
|
428
|
+
|
|
429
|
+
const context = {
|
|
430
|
+
sourceRoot,
|
|
431
|
+
projectRoot,
|
|
432
|
+
homeDir,
|
|
433
|
+
languages: Array.isArray(options.languages) ? options.languages : [],
|
|
434
|
+
claudeRulesDir: options.claudeRulesDir || process.env.CLAUDE_RULES_DIR || null,
|
|
435
|
+
};
|
|
436
|
+
|
|
437
|
+
let plan;
|
|
438
|
+
if (target === 'claude') {
|
|
439
|
+
plan = planClaudeLegacyInstall(context);
|
|
440
|
+
} else if (target === 'cursor') {
|
|
441
|
+
plan = planCursorLegacyInstall(context);
|
|
442
|
+
} else {
|
|
443
|
+
plan = planAntigravityLegacyInstall(context);
|
|
444
|
+
}
|
|
445
|
+
|
|
446
|
+
const source = {
|
|
447
|
+
repoVersion: getPackageVersion(sourceRoot),
|
|
448
|
+
repoCommit: getRepoCommit(sourceRoot),
|
|
449
|
+
manifestVersion: getManifestVersion(sourceRoot),
|
|
450
|
+
};
|
|
451
|
+
|
|
452
|
+
const statePreview = createInstallState({
|
|
453
|
+
adapter: plan.adapter,
|
|
454
|
+
targetRoot: plan.targetRoot,
|
|
455
|
+
installStatePath: plan.installStatePath,
|
|
456
|
+
request: {
|
|
457
|
+
profile: null,
|
|
458
|
+
modules: [],
|
|
459
|
+
legacyLanguages: context.languages,
|
|
460
|
+
legacyMode: true,
|
|
461
|
+
},
|
|
462
|
+
resolution: {
|
|
463
|
+
selectedModules: plan.selectedModules,
|
|
464
|
+
skippedModules: [],
|
|
465
|
+
},
|
|
466
|
+
operations: plan.operations,
|
|
467
|
+
source,
|
|
468
|
+
});
|
|
469
|
+
|
|
470
|
+
return {
|
|
471
|
+
mode: 'legacy',
|
|
472
|
+
target: plan.target,
|
|
473
|
+
adapter: {
|
|
474
|
+
id: plan.adapter.id,
|
|
475
|
+
target: plan.adapter.target,
|
|
476
|
+
kind: plan.adapter.kind,
|
|
477
|
+
},
|
|
478
|
+
targetRoot: plan.targetRoot,
|
|
479
|
+
installRoot: plan.installRoot,
|
|
480
|
+
installStatePath: plan.installStatePath,
|
|
481
|
+
warnings: plan.warnings,
|
|
482
|
+
languages: context.languages,
|
|
483
|
+
operations: plan.operations,
|
|
484
|
+
statePreview,
|
|
485
|
+
};
|
|
486
|
+
}
|
|
487
|
+
|
|
488
|
+
function materializeScaffoldOperation(sourceRoot, operation) {
|
|
489
|
+
const sourcePath = path.join(sourceRoot, operation.sourceRelativePath);
|
|
490
|
+
if (!fs.existsSync(sourcePath)) {
|
|
491
|
+
return [];
|
|
492
|
+
}
|
|
493
|
+
|
|
494
|
+
if (isGeneratedRuntimeSourcePath(operation.sourceRelativePath)) {
|
|
495
|
+
return [];
|
|
496
|
+
}
|
|
497
|
+
|
|
498
|
+
const stat = fs.statSync(sourcePath);
|
|
499
|
+
if (stat.isFile()) {
|
|
500
|
+
return [buildCopyFileOperation({
|
|
501
|
+
moduleId: operation.moduleId,
|
|
502
|
+
sourcePath,
|
|
503
|
+
sourceRelativePath: operation.sourceRelativePath,
|
|
504
|
+
destinationPath: operation.destinationPath,
|
|
505
|
+
strategy: operation.strategy,
|
|
506
|
+
})];
|
|
507
|
+
}
|
|
508
|
+
|
|
509
|
+
const relativeFiles = listFilesRecursive(sourcePath).filter(relativeFile => {
|
|
510
|
+
const sourceRelativePath = path.join(operation.sourceRelativePath, relativeFile);
|
|
511
|
+
return !isGeneratedRuntimeSourcePath(sourceRelativePath);
|
|
512
|
+
});
|
|
513
|
+
return relativeFiles.map(relativeFile => {
|
|
514
|
+
const sourceRelativePath = path.join(operation.sourceRelativePath, relativeFile);
|
|
515
|
+
return buildCopyFileOperation({
|
|
516
|
+
moduleId: operation.moduleId,
|
|
517
|
+
sourcePath: path.join(sourcePath, relativeFile),
|
|
518
|
+
sourceRelativePath,
|
|
519
|
+
destinationPath: path.join(operation.destinationPath, relativeFile),
|
|
520
|
+
strategy: operation.strategy,
|
|
521
|
+
});
|
|
522
|
+
});
|
|
523
|
+
}
|
|
524
|
+
|
|
525
|
+
function createManifestInstallPlan(options = {}) {
|
|
526
|
+
const sourceRoot = options.sourceRoot || getSourceRoot();
|
|
527
|
+
const projectRoot = options.projectRoot || process.cwd();
|
|
528
|
+
const target = options.target || 'claude';
|
|
529
|
+
const plan = resolveInstallPlan({
|
|
530
|
+
repoRoot: sourceRoot,
|
|
531
|
+
projectRoot,
|
|
532
|
+
homeDir: options.homeDir,
|
|
533
|
+
profileId: options.profileId || null,
|
|
534
|
+
moduleIds: options.moduleIds || [],
|
|
535
|
+
includeComponentIds: options.includeComponentIds || [],
|
|
536
|
+
excludeComponentIds: options.excludeComponentIds || [],
|
|
537
|
+
target,
|
|
538
|
+
});
|
|
539
|
+
const adapter = getInstallTargetAdapter(target);
|
|
540
|
+
const operations = plan.operations.flatMap(operation => materializeScaffoldOperation(sourceRoot, operation));
|
|
541
|
+
const source = {
|
|
542
|
+
repoVersion: getPackageVersion(sourceRoot),
|
|
543
|
+
repoCommit: getRepoCommit(sourceRoot),
|
|
544
|
+
manifestVersion: getManifestVersion(sourceRoot),
|
|
545
|
+
};
|
|
546
|
+
const statePreview = createInstallState({
|
|
547
|
+
adapter,
|
|
548
|
+
targetRoot: plan.targetRoot,
|
|
549
|
+
installStatePath: plan.installStatePath,
|
|
550
|
+
request: {
|
|
551
|
+
profile: plan.profileId,
|
|
552
|
+
modules: Array.isArray(options.moduleIds) ? [...options.moduleIds] : [],
|
|
553
|
+
includeComponents: Array.isArray(options.includeComponentIds)
|
|
554
|
+
? [...options.includeComponentIds]
|
|
555
|
+
: [],
|
|
556
|
+
excludeComponents: Array.isArray(options.excludeComponentIds)
|
|
557
|
+
? [...options.excludeComponentIds]
|
|
558
|
+
: [],
|
|
559
|
+
legacyLanguages: [],
|
|
560
|
+
legacyMode: false,
|
|
561
|
+
},
|
|
562
|
+
resolution: {
|
|
563
|
+
selectedModules: plan.selectedModuleIds,
|
|
564
|
+
skippedModules: plan.skippedModuleIds,
|
|
565
|
+
},
|
|
566
|
+
operations,
|
|
567
|
+
source,
|
|
568
|
+
});
|
|
569
|
+
|
|
570
|
+
return {
|
|
571
|
+
mode: 'manifest',
|
|
572
|
+
target,
|
|
573
|
+
adapter: {
|
|
574
|
+
id: adapter.id,
|
|
575
|
+
target: adapter.target,
|
|
576
|
+
kind: adapter.kind,
|
|
577
|
+
},
|
|
578
|
+
targetRoot: plan.targetRoot,
|
|
579
|
+
installRoot: plan.targetRoot,
|
|
580
|
+
installStatePath: plan.installStatePath,
|
|
581
|
+
warnings: [],
|
|
582
|
+
languages: [],
|
|
583
|
+
profileId: plan.profileId,
|
|
584
|
+
requestedModuleIds: plan.requestedModuleIds,
|
|
585
|
+
explicitModuleIds: plan.explicitModuleIds,
|
|
586
|
+
includedComponentIds: plan.includedComponentIds,
|
|
587
|
+
excludedComponentIds: plan.excludedComponentIds,
|
|
588
|
+
selectedModuleIds: plan.selectedModuleIds,
|
|
589
|
+
skippedModuleIds: plan.skippedModuleIds,
|
|
590
|
+
excludedModuleIds: plan.excludedModuleIds,
|
|
591
|
+
operations,
|
|
592
|
+
statePreview,
|
|
593
|
+
};
|
|
594
|
+
}
|
|
595
|
+
|
|
596
|
+
module.exports = {
|
|
597
|
+
SUPPORTED_INSTALL_TARGETS,
|
|
598
|
+
LEGACY_INSTALL_TARGETS,
|
|
599
|
+
applyInstallPlan,
|
|
600
|
+
createManifestInstallPlan,
|
|
601
|
+
createLegacyInstallPlan,
|
|
602
|
+
getSourceRoot,
|
|
603
|
+
listAvailableLanguages,
|
|
604
|
+
parseInstallArgs,
|
|
605
|
+
};
|