@inkeep/agents-cli 0.51.0 → 0.53.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/dist/agents-cli/package.js +6 -0
- package/dist/commands/config.js +1 -1
- package/dist/commands/dev.js +1 -1
- package/dist/commands/init.js +1 -1
- package/dist/commands/{pull-v3 → pull-v4}/component-parser.js +6 -12
- package/dist/commands/{pull-v3/utils → pull-v4}/component-registry.js +1 -1
- package/dist/commands/pull-v4/generators/agent-generator.js +258 -0
- package/dist/commands/pull-v4/generators/artifact-component-generator.js +69 -0
- package/dist/commands/pull-v4/generators/context-config-generator.js +264 -0
- package/dist/commands/pull-v4/generators/credential-generator.js +30 -0
- package/dist/commands/pull-v4/generators/data-component-generator.js +50 -0
- package/dist/commands/pull-v4/generators/environment-generator.js +123 -0
- package/dist/commands/pull-v4/generators/external-agent-generator.js +56 -0
- package/dist/commands/pull-v4/generators/function-tool-generator.js +48 -0
- package/dist/commands/pull-v4/generators/mcp-tool-generator.js +91 -0
- package/dist/commands/pull-v4/generators/project-generator.js +125 -0
- package/dist/commands/{pull-v3/components → pull-v4/generators}/skill-generator.js +1 -1
- package/dist/commands/pull-v4/generators/status-component-generator.js +35 -0
- package/dist/commands/pull-v4/generators/sub-agent-generator.js +269 -0
- package/dist/commands/pull-v4/generators/trigger-generator.js +58 -0
- package/dist/commands/pull-v4/introspect/index.js +365 -0
- package/dist/commands/pull-v4/introspect/test-helpers.js +143 -0
- package/dist/commands/pull-v4/introspect-generator.js +706 -0
- package/dist/commands/pull-v4/module-merge.js +405 -0
- package/dist/commands/pull-v4/utils.js +235 -0
- package/dist/commands/push.js +1 -1
- package/dist/commands/update.js +2 -2
- package/dist/index.js +18 -44
- package/dist/node_modules/.pnpm/diff@8.0.3/node_modules/diff/libesm/diff/array.js +18 -0
- package/dist/node_modules/.pnpm/diff@8.0.3/node_modules/diff/libesm/diff/base.js +180 -0
- package/dist/node_modules/.pnpm/diff@8.0.3/node_modules/diff/libesm/diff/character.js +8 -0
- package/dist/node_modules/.pnpm/diff@8.0.3/node_modules/diff/libesm/diff/css.js +12 -0
- package/dist/node_modules/.pnpm/diff@8.0.3/node_modules/diff/libesm/diff/json.js +60 -0
- package/dist/node_modules/.pnpm/diff@8.0.3/node_modules/diff/libesm/diff/line.js +37 -0
- package/dist/node_modules/.pnpm/diff@8.0.3/node_modules/diff/libesm/diff/sentence.js +31 -0
- package/dist/node_modules/.pnpm/diff@8.0.3/node_modules/diff/libesm/diff/word.js +118 -0
- package/dist/node_modules/.pnpm/diff@8.0.3/node_modules/diff/libesm/index.js +11 -0
- package/dist/node_modules/.pnpm/diff@8.0.3/node_modules/diff/libesm/patch/create.js +141 -0
- package/dist/node_modules/.pnpm/diff@8.0.3/node_modules/diff/libesm/util/string.js +63 -0
- package/dist/utils/ci-environment.js +1 -1
- package/dist/utils/config.js +1 -1
- package/dist/utils/environment-loader.js +1 -1
- package/dist/utils/file-finder.js +1 -1
- package/dist/utils/mcp-runner.js +1 -1
- package/dist/utils/profile-config.js +1 -1
- package/dist/utils/profiles/profile-manager.js +1 -1
- package/dist/utils/project-directory.js +1 -1
- package/dist/utils/project-loader.js +1 -1
- package/dist/utils/version-check.js +6 -15
- package/package.json +5 -7
- package/dist/commands/pull-v3/component-updater.js +0 -768
- package/dist/commands/pull-v3/components/agent-generator.js +0 -255
- package/dist/commands/pull-v3/components/artifact-component-generator.js +0 -143
- package/dist/commands/pull-v3/components/context-config-generator.js +0 -190
- package/dist/commands/pull-v3/components/credential-generator.js +0 -89
- package/dist/commands/pull-v3/components/data-component-generator.js +0 -102
- package/dist/commands/pull-v3/components/environment-generator.js +0 -173
- package/dist/commands/pull-v3/components/external-agent-generator.js +0 -75
- package/dist/commands/pull-v3/components/function-tool-generator.js +0 -92
- package/dist/commands/pull-v3/components/mcp-tool-generator.js +0 -86
- package/dist/commands/pull-v3/components/project-generator.js +0 -157
- package/dist/commands/pull-v3/components/status-component-generator.js +0 -92
- package/dist/commands/pull-v3/components/sub-agent-generator.js +0 -295
- package/dist/commands/pull-v3/components/trigger-generator.js +0 -185
- package/dist/commands/pull-v3/index.js +0 -510
- package/dist/commands/pull-v3/introspect-generator.js +0 -286
- package/dist/commands/pull-v3/llm-content-merger.js +0 -192
- package/dist/commands/pull-v3/new-component-generator.js +0 -279
- package/dist/commands/pull-v3/project-comparator.js +0 -914
- package/dist/commands/pull-v3/project-index-generator.js +0 -32
- package/dist/commands/pull-v3/project-validator.js +0 -358
- package/dist/commands/pull-v3/targeted-typescript-placeholders.js +0 -173
- package/dist/commands/pull-v3/utils/component-tracker.js +0 -165
- package/dist/commands/pull-v3/utils/generator-utils.js +0 -146
- package/dist/commands/pull-v3/utils/model-provider-detector.js +0 -50
- package/dist/utils/url.js +0 -26
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
import { generateProjectFile } from "./components/project-generator.js";
|
|
2
|
-
import { writeFileSync } from "node:fs";
|
|
3
|
-
import { join } from "node:path";
|
|
4
|
-
|
|
5
|
-
//#region src/commands/pull-v3/project-index-generator.ts
|
|
6
|
-
/**
|
|
7
|
-
* Project Index Generator - Generate index.ts file for new projects
|
|
8
|
-
*/
|
|
9
|
-
/**
|
|
10
|
-
* Generate project index.ts file
|
|
11
|
-
*/
|
|
12
|
-
async function generateProjectIndex(projectRoot, remoteProject, localRegistry, projectId) {
|
|
13
|
-
const indexPath = join(projectRoot, "index.ts");
|
|
14
|
-
const defaultStyle = {
|
|
15
|
-
quotes: "single",
|
|
16
|
-
indentation: " ",
|
|
17
|
-
semicolons: true
|
|
18
|
-
};
|
|
19
|
-
const registryComponents = localRegistry.getAllComponents();
|
|
20
|
-
writeFileSync(indexPath, generateProjectFile(projectId, {
|
|
21
|
-
...remoteProject,
|
|
22
|
-
agents: registryComponents.filter((c) => c.type === "agents").map((c) => c.id),
|
|
23
|
-
tools: registryComponents.filter((c) => c.type === "tools").map((c) => c.id),
|
|
24
|
-
externalAgents: registryComponents.filter((c) => c.type === "externalAgents").map((c) => c.id),
|
|
25
|
-
dataComponents: registryComponents.filter((c) => c.type === "dataComponents").map((c) => c.id),
|
|
26
|
-
artifactComponents: registryComponents.filter((c) => c.type === "artifactComponents").map((c) => c.id),
|
|
27
|
-
credentialReferences: registryComponents.filter((c) => c.type === "credentials").map((c) => c.id)
|
|
28
|
-
}, defaultStyle, localRegistry), "utf8");
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
//#endregion
|
|
32
|
-
export { generateProjectIndex };
|
|
@@ -1,358 +0,0 @@
|
|
|
1
|
-
import { compareProjects } from "./project-comparator.js";
|
|
2
|
-
import { enrichCanDelegateToWithTypes } from "./index.js";
|
|
3
|
-
import { buildComponentRegistryFromParsing } from "./component-parser.js";
|
|
4
|
-
import { copyFileSync, existsSync, mkdirSync, readdirSync, rmSync, statSync } from "node:fs";
|
|
5
|
-
import { dirname, join } from "node:path";
|
|
6
|
-
import chalk from "chalk";
|
|
7
|
-
|
|
8
|
-
//#region src/commands/pull-v3/project-validator.ts
|
|
9
|
-
/**
|
|
10
|
-
* Project Validator - Validate generated projects with TypeScript compilation and equivalence checking
|
|
11
|
-
*/
|
|
12
|
-
/**
|
|
13
|
-
* Get a complete preview of an object for logging (pretty-printed JSON)
|
|
14
|
-
*/
|
|
15
|
-
function getObjectPreview(obj) {
|
|
16
|
-
if (obj === null) return "null";
|
|
17
|
-
if (obj === void 0) return "undefined";
|
|
18
|
-
try {
|
|
19
|
-
if (typeof obj === "object") return JSON.stringify(obj, null, 2);
|
|
20
|
-
return String(obj);
|
|
21
|
-
} catch {
|
|
22
|
-
return `[Error stringifying: ${typeof obj}]`;
|
|
23
|
-
}
|
|
24
|
-
}
|
|
25
|
-
/**
|
|
26
|
-
* Find key differences between two objects without full JSON dump
|
|
27
|
-
*/
|
|
28
|
-
/**
|
|
29
|
-
* Extract credential IDs from an agent object, handling different storage structures
|
|
30
|
-
*/
|
|
31
|
-
function extractCredentialIds(agentObj) {
|
|
32
|
-
const credentialIds = [];
|
|
33
|
-
if (agentObj.credentials && Array.isArray(agentObj.credentials)) agentObj.credentials.forEach((cred) => {
|
|
34
|
-
if (cred.id) credentialIds.push(cred.id);
|
|
35
|
-
});
|
|
36
|
-
if (agentObj.contextConfig?.contextVariables) Object.values(agentObj.contextConfig.contextVariables).forEach((variable) => {
|
|
37
|
-
if (variable && typeof variable === "object" && variable.credentialReferenceId) credentialIds.push(variable.credentialReferenceId);
|
|
38
|
-
});
|
|
39
|
-
return [...new Set(credentialIds)];
|
|
40
|
-
}
|
|
41
|
-
const IGNORED_COMPARISON_FIELDS = new Set([
|
|
42
|
-
"type",
|
|
43
|
-
"tenantId",
|
|
44
|
-
"projectId",
|
|
45
|
-
"agentId",
|
|
46
|
-
"lastError",
|
|
47
|
-
"lastErrorAt",
|
|
48
|
-
"status",
|
|
49
|
-
"usedBy",
|
|
50
|
-
"tools",
|
|
51
|
-
"createdAt",
|
|
52
|
-
"updatedAt"
|
|
53
|
-
]);
|
|
54
|
-
function findKeyDifferences(obj1, obj2) {
|
|
55
|
-
const differences = [];
|
|
56
|
-
const allKeys = new Set([...Object.keys(obj1 || {}), ...Object.keys(obj2 || {})]);
|
|
57
|
-
for (const key of allKeys) {
|
|
58
|
-
const val1 = obj1?.[key];
|
|
59
|
-
const val2 = obj2?.[key];
|
|
60
|
-
if (key.startsWith("_") || IGNORED_COMPARISON_FIELDS.has(key)) continue;
|
|
61
|
-
if (key === "credentials") {
|
|
62
|
-
const creds1 = extractCredentialIds(obj1);
|
|
63
|
-
const creds2 = extractCredentialIds(obj2);
|
|
64
|
-
creds1.sort();
|
|
65
|
-
creds2.sort();
|
|
66
|
-
if (JSON.stringify(creds1) !== JSON.stringify(creds2)) differences.push(`~ credentials: usage differs (${creds1.join(", ")} vs ${creds2.join(", ")})`);
|
|
67
|
-
continue;
|
|
68
|
-
}
|
|
69
|
-
const val1IsEmpty = val1 === null || val1 === void 0 || Array.isArray(val1) && val1.length === 0 || typeof val1 === "object" && val1 !== null && Object.keys(val1).length === 0;
|
|
70
|
-
const val2IsEmpty = val2 === null || val2 === void 0 || Array.isArray(val2) && val2.length === 0 || typeof val2 === "object" && val2 !== null && Object.keys(val2).length === 0;
|
|
71
|
-
if (val1IsEmpty && val2IsEmpty) continue;
|
|
72
|
-
if (val1IsEmpty && !val2IsEmpty) differences.push(`+ ${key}: ${typeof val2} (only in remote)`);
|
|
73
|
-
else if (!val1IsEmpty && val2IsEmpty) differences.push(`- ${key}: ${typeof val1} (only in generated)`);
|
|
74
|
-
else if (val1 !== val2) if (Array.isArray(val1) && Array.isArray(val2)) {
|
|
75
|
-
if (val1.length !== val2.length) differences.push(`~ ${key}: array length differs (${val1.length} vs ${val2.length})`);
|
|
76
|
-
} else if (typeof val1 === "object" && typeof val2 === "object" && val1 !== null && val2 !== null) {
|
|
77
|
-
const filterKeys = (obj) => Object.keys(obj).filter((k) => {
|
|
78
|
-
if (k.startsWith("_") || IGNORED_COMPARISON_FIELDS.has(k)) return false;
|
|
79
|
-
const v = obj[k];
|
|
80
|
-
return !(v === null || v === void 0 || Array.isArray(v) && v.length === 0 || typeof v === "object" && v !== null && Object.keys(v).length === 0);
|
|
81
|
-
});
|
|
82
|
-
const keys1 = filterKeys(val1);
|
|
83
|
-
const keys2 = filterKeys(val2);
|
|
84
|
-
const subKeys1 = keys1.length;
|
|
85
|
-
const subKeys2 = keys2.length;
|
|
86
|
-
if (subKeys1 !== subKeys2) differences.push(`~ ${key}: object size differs (${subKeys1} vs ${subKeys2} keys)`);
|
|
87
|
-
} else if (typeof val1 !== typeof val2) differences.push(`~ ${key}: type differs (${typeof val1} vs ${typeof val2})`);
|
|
88
|
-
else if (key === "render" || key === "component") {
|
|
89
|
-
const val1Preview = getObjectPreview(val1);
|
|
90
|
-
const val2Preview = getObjectPreview(val2);
|
|
91
|
-
differences.push(`~ ${key}:`);
|
|
92
|
-
differences.push(` Generated: ${val1Preview}`);
|
|
93
|
-
differences.push(` Remote: ${val2Preview}`);
|
|
94
|
-
} else {
|
|
95
|
-
const val1Str = String(val1);
|
|
96
|
-
const val2Str = String(val2);
|
|
97
|
-
if (val1Str.length < 100 && val2Str.length < 100) differences.push(`~ ${key}: "${val1Str}" vs "${val2Str}"`);
|
|
98
|
-
else differences.push(`~ ${key}: values differ (both ${typeof val1})`);
|
|
99
|
-
}
|
|
100
|
-
}
|
|
101
|
-
return differences.slice(0, 10);
|
|
102
|
-
}
|
|
103
|
-
/**
|
|
104
|
-
* Get a specific component from a project by type and ID
|
|
105
|
-
*/
|
|
106
|
-
function getComponentFromProject(project, componentType, componentId) {
|
|
107
|
-
switch (componentType) {
|
|
108
|
-
case "credentials": return project.credentialReferences?.[componentId];
|
|
109
|
-
case "tools": return project.tools?.[componentId];
|
|
110
|
-
case "agents": return project.agents?.[componentId];
|
|
111
|
-
case "subAgents":
|
|
112
|
-
if (project.agents) {
|
|
113
|
-
for (const [_agentId, agentData] of Object.entries(project.agents)) if (agentData.subAgents?.[componentId]) return agentData.subAgents[componentId];
|
|
114
|
-
}
|
|
115
|
-
return null;
|
|
116
|
-
case "contextConfigs":
|
|
117
|
-
if (project.agents) {
|
|
118
|
-
for (const [_agentId, agentData] of Object.entries(project.agents)) if (agentData.contextConfig && agentData.contextConfig.id === componentId) return agentData.contextConfig;
|
|
119
|
-
}
|
|
120
|
-
return null;
|
|
121
|
-
case "fetchDefinitions":
|
|
122
|
-
if (project.agents) {
|
|
123
|
-
for (const [_agentId, agentData] of Object.entries(project.agents)) if (agentData.contextConfig?.contextVariables) {
|
|
124
|
-
for (const [_varId, variable] of Object.entries(agentData.contextConfig.contextVariables)) if (variable && typeof variable === "object" && variable.id === componentId) return variable;
|
|
125
|
-
}
|
|
126
|
-
}
|
|
127
|
-
return null;
|
|
128
|
-
case "dataComponents": return project.dataComponents?.[componentId];
|
|
129
|
-
case "artifactComponents": return project.artifactComponents?.[componentId];
|
|
130
|
-
case "externalAgents": return project.externalAgents?.[componentId];
|
|
131
|
-
case "functions": return project.functions?.[componentId];
|
|
132
|
-
case "functionTools": return project.functionTools?.[componentId];
|
|
133
|
-
default: return null;
|
|
134
|
-
}
|
|
135
|
-
}
|
|
136
|
-
/**
|
|
137
|
-
* Load project from temp directory and compare with remote project
|
|
138
|
-
*/
|
|
139
|
-
async function validateProjectEquivalence(tempDir, remoteProject) {
|
|
140
|
-
try {
|
|
141
|
-
const { loadProject } = await import("../../utils/project-loader.js");
|
|
142
|
-
const tempProject = await loadProject(tempDir);
|
|
143
|
-
const tempProjectDefinition = await Promise.race([tempProject.getFullDefinition(), new Promise((_, reject) => {
|
|
144
|
-
setTimeout(() => {
|
|
145
|
-
reject(/* @__PURE__ */ new Error("getFullDefinition() timed out after 30 seconds"));
|
|
146
|
-
}, 3e4);
|
|
147
|
-
})]);
|
|
148
|
-
enrichCanDelegateToWithTypes(tempProjectDefinition);
|
|
149
|
-
buildComponentRegistryFromParsing(tempDir, false);
|
|
150
|
-
const comparison = await compareProjects(tempProjectDefinition, remoteProject, true);
|
|
151
|
-
if (!comparison.hasChanges) return true;
|
|
152
|
-
let hasMeaningfulDifferences = false;
|
|
153
|
-
let hasAddedOrDeleted = false;
|
|
154
|
-
const meaningfulDiffs = [];
|
|
155
|
-
const addedComponents = [];
|
|
156
|
-
const deletedComponents = [];
|
|
157
|
-
for (const [componentType, changes] of Object.entries(comparison.componentChanges)) {
|
|
158
|
-
if (changes.added.length > 0) {
|
|
159
|
-
addedComponents.push({
|
|
160
|
-
type: componentType,
|
|
161
|
-
ids: changes.added
|
|
162
|
-
});
|
|
163
|
-
hasAddedOrDeleted = true;
|
|
164
|
-
}
|
|
165
|
-
if (changes.deleted.length > 0) {
|
|
166
|
-
deletedComponents.push({
|
|
167
|
-
type: componentType,
|
|
168
|
-
ids: changes.deleted
|
|
169
|
-
});
|
|
170
|
-
hasAddedOrDeleted = true;
|
|
171
|
-
}
|
|
172
|
-
if (changes.modified.length > 0) for (const modifiedId of changes.modified) {
|
|
173
|
-
const generatedComponent = getComponentFromProject(tempProjectDefinition, componentType, modifiedId);
|
|
174
|
-
const remoteComponent = getComponentFromProject(remoteProject, componentType, modifiedId);
|
|
175
|
-
if (generatedComponent && remoteComponent) {
|
|
176
|
-
const differences = findKeyDifferences(generatedComponent, remoteComponent);
|
|
177
|
-
if (differences.length > 0) {
|
|
178
|
-
meaningfulDiffs.push({
|
|
179
|
-
componentType,
|
|
180
|
-
componentId: modifiedId,
|
|
181
|
-
differences
|
|
182
|
-
});
|
|
183
|
-
hasMeaningfulDifferences = true;
|
|
184
|
-
}
|
|
185
|
-
} else if (!generatedComponent) {
|
|
186
|
-
meaningfulDiffs.push({
|
|
187
|
-
componentType,
|
|
188
|
-
componentId: modifiedId,
|
|
189
|
-
differences: [],
|
|
190
|
-
isMissing: "generated"
|
|
191
|
-
});
|
|
192
|
-
hasMeaningfulDifferences = true;
|
|
193
|
-
} else if (!remoteComponent) {
|
|
194
|
-
meaningfulDiffs.push({
|
|
195
|
-
componentType,
|
|
196
|
-
componentId: modifiedId,
|
|
197
|
-
differences: [],
|
|
198
|
-
isMissing: "remote"
|
|
199
|
-
});
|
|
200
|
-
hasMeaningfulDifferences = true;
|
|
201
|
-
}
|
|
202
|
-
}
|
|
203
|
-
}
|
|
204
|
-
if (!hasMeaningfulDifferences && !hasAddedOrDeleted) return true;
|
|
205
|
-
console.log(chalk.yellow(` 🔄 Found differences:`));
|
|
206
|
-
for (const { type, ids } of addedComponents) {
|
|
207
|
-
console.log(chalk.cyan(` ${type}:`));
|
|
208
|
-
console.log(chalk.green(` ➕ Added: ${ids.join(", ")}`));
|
|
209
|
-
}
|
|
210
|
-
for (const { type, ids } of deletedComponents) {
|
|
211
|
-
console.log(chalk.cyan(` ${type}:`));
|
|
212
|
-
console.log(chalk.red(` ➖ Deleted: ${ids.join(", ")}`));
|
|
213
|
-
}
|
|
214
|
-
const modifiedByType = /* @__PURE__ */ new Map();
|
|
215
|
-
for (const diff of meaningfulDiffs) {
|
|
216
|
-
const existing = modifiedByType.get(diff.componentType) ?? [];
|
|
217
|
-
existing.push(diff);
|
|
218
|
-
modifiedByType.set(diff.componentType, existing);
|
|
219
|
-
}
|
|
220
|
-
for (const [componentType, diffs] of modifiedByType) {
|
|
221
|
-
console.log(chalk.cyan(` ${componentType}:`));
|
|
222
|
-
console.log(chalk.yellow(` 📝 Modified: ${diffs.map((d) => d.componentId).join(", ")}`));
|
|
223
|
-
for (const diff of diffs) {
|
|
224
|
-
console.log(chalk.gray(` ${diff.componentId} detailed differences:`));
|
|
225
|
-
if (diff.isMissing === "generated") console.log(chalk.red(` Component missing in generated project`));
|
|
226
|
-
else if (diff.isMissing === "remote") console.log(chalk.red(` Component missing in remote project`));
|
|
227
|
-
else for (const d of diff.differences) console.log(chalk.gray(` ${d}`));
|
|
228
|
-
}
|
|
229
|
-
}
|
|
230
|
-
return false;
|
|
231
|
-
} catch (error) {
|
|
232
|
-
const errorMsg = error instanceof Error ? error.message : String(error);
|
|
233
|
-
console.log(chalk.red(` ❌ Project validation failed: ${errorMsg}`));
|
|
234
|
-
return false;
|
|
235
|
-
}
|
|
236
|
-
}
|
|
237
|
-
let isWaitingForInput = false;
|
|
238
|
-
let currentKeypressHandler = null;
|
|
239
|
-
async function validateTempDirectory(originalProjectRoot, tempDirName, remoteProject, options) {
|
|
240
|
-
const tempDir = join(originalProjectRoot, tempDirName);
|
|
241
|
-
const skipExit = options?.skipExit ?? false;
|
|
242
|
-
if (await validateProjectEquivalence(tempDir, remoteProject)) {
|
|
243
|
-
console.log(chalk.green(`\n✅ Project is already up to date - no meaningful changes detected`));
|
|
244
|
-
console.log(chalk.gray(` Cleaning up temp directory...`));
|
|
245
|
-
try {
|
|
246
|
-
rmSync(tempDir, {
|
|
247
|
-
recursive: true,
|
|
248
|
-
force: true
|
|
249
|
-
});
|
|
250
|
-
console.log(chalk.gray(` Temp directory cleaned up.`));
|
|
251
|
-
} catch {
|
|
252
|
-
console.log(chalk.yellow(` Note: Could not clean up temp directory: ${tempDirName}`));
|
|
253
|
-
}
|
|
254
|
-
console.log(chalk.green(`\n🎉 Pull completed - project is up to date!`));
|
|
255
|
-
if (!skipExit) process.exit(0);
|
|
256
|
-
return {
|
|
257
|
-
success: true,
|
|
258
|
-
upToDate: true
|
|
259
|
-
};
|
|
260
|
-
}
|
|
261
|
-
console.log(chalk.yellow(`\n❓ Would you like to overwrite your project files with the generated files?`));
|
|
262
|
-
console.log(chalk.gray(` This will replace your current files with the validated generated ones.`));
|
|
263
|
-
console.log(chalk.green(` [Y] Yes - Replace files and clean up temp directory`));
|
|
264
|
-
console.log(chalk.red(` [N] No - Keep temp directory for manual review`));
|
|
265
|
-
return new Promise((resolve$1) => {
|
|
266
|
-
if (isWaitingForInput && currentKeypressHandler) process.stdin.removeListener("data", currentKeypressHandler);
|
|
267
|
-
process.stdin.removeAllListeners("data");
|
|
268
|
-
process.stdin.removeAllListeners("keypress");
|
|
269
|
-
process.stdin.removeAllListeners("end");
|
|
270
|
-
if (process.stdin.isTTY && !process.stdin.isRaw) process.stdin.setRawMode(true);
|
|
271
|
-
if (process.stdin.isPaused()) process.stdin.resume();
|
|
272
|
-
process.stdin.setEncoding("utf8");
|
|
273
|
-
const onKeypress = (key) => {
|
|
274
|
-
if (!isWaitingForInput) return;
|
|
275
|
-
isWaitingForInput = false;
|
|
276
|
-
currentKeypressHandler = null;
|
|
277
|
-
process.stdin.removeAllListeners("data");
|
|
278
|
-
process.stdin.removeAllListeners("keypress");
|
|
279
|
-
process.stdin.removeAllListeners("end");
|
|
280
|
-
if (process.stdin.isTTY) process.stdin.setRawMode(false);
|
|
281
|
-
process.stdin.pause();
|
|
282
|
-
const normalizedKey = key.toLowerCase();
|
|
283
|
-
if (normalizedKey === "y") {
|
|
284
|
-
console.log(chalk.green(`\n✅ Selected: Yes - Replacing files...`));
|
|
285
|
-
overwriteProjectFiles(originalProjectRoot, tempDirName, tempDir);
|
|
286
|
-
console.log(chalk.green(`\n🎉 Pull completed successfully!`));
|
|
287
|
-
if (!skipExit) process.exit(0);
|
|
288
|
-
resolve$1({ success: true });
|
|
289
|
-
} else if (normalizedKey === "n") {
|
|
290
|
-
console.log(chalk.yellow(`\n❌ Selected: No - Files not replaced`));
|
|
291
|
-
console.log(chalk.gray(`📂 Generated files remain in: ${tempDirName}`));
|
|
292
|
-
console.log(chalk.gray(` You can manually review and copy files as needed.`));
|
|
293
|
-
console.log(chalk.cyan(`\n✅ Pull completed - temp directory preserved for review.`));
|
|
294
|
-
if (!skipExit) process.exit(0);
|
|
295
|
-
resolve$1({
|
|
296
|
-
success: true,
|
|
297
|
-
userDeclined: true
|
|
298
|
-
});
|
|
299
|
-
} else {
|
|
300
|
-
console.log(chalk.red(`\n❌ Invalid key: "${key}". Please press Y or N.`));
|
|
301
|
-
console.log(chalk.gray(`📂 Files not replaced. Generated files remain in: ${tempDirName}`));
|
|
302
|
-
console.log(chalk.yellow(`\n⚠️ Pull completed with invalid input - temp directory preserved.`));
|
|
303
|
-
if (!skipExit) process.exit(0);
|
|
304
|
-
resolve$1({
|
|
305
|
-
success: true,
|
|
306
|
-
userDeclined: true
|
|
307
|
-
});
|
|
308
|
-
}
|
|
309
|
-
};
|
|
310
|
-
currentKeypressHandler = onKeypress;
|
|
311
|
-
isWaitingForInput = true;
|
|
312
|
-
process.stdin.once("data", onKeypress);
|
|
313
|
-
process.stdout.write(chalk.cyan("\nPress [Y] for Yes or [N] for No: "));
|
|
314
|
-
});
|
|
315
|
-
}
|
|
316
|
-
/**
|
|
317
|
-
* Overwrite project files with validated temp directory files and clean up
|
|
318
|
-
*/
|
|
319
|
-
function overwriteProjectFiles(originalProjectRoot, tempDirName, tempDir) {
|
|
320
|
-
try {
|
|
321
|
-
console.log(chalk.cyan(`\n🔄 Replacing project files with generated files...`));
|
|
322
|
-
let filesReplaced = 0;
|
|
323
|
-
function copyRecursively(sourceDir, targetDir) {
|
|
324
|
-
if (!existsSync(sourceDir)) return;
|
|
325
|
-
const entries = readdirSync(sourceDir);
|
|
326
|
-
for (const entry of entries) {
|
|
327
|
-
if (entry.startsWith(".temp-") || entry.startsWith(".DS_Store") || entry === "node_modules" || entry === ".git" || entry === "tsconfig.json" || entry === "package.json") continue;
|
|
328
|
-
const sourcePath = join(sourceDir, entry);
|
|
329
|
-
const targetPath = join(targetDir, entry);
|
|
330
|
-
const stat = statSync(sourcePath);
|
|
331
|
-
if (stat.isDirectory()) copyRecursively(sourcePath, targetPath);
|
|
332
|
-
else if (stat.isFile()) {
|
|
333
|
-
mkdirSync(dirname(targetPath), { recursive: true });
|
|
334
|
-
copyFileSync(sourcePath, targetPath);
|
|
335
|
-
filesReplaced++;
|
|
336
|
-
const relativePath = targetPath.replace(`${originalProjectRoot}/`, "");
|
|
337
|
-
console.log(chalk.green(` ✅ Replaced: ${relativePath}`));
|
|
338
|
-
}
|
|
339
|
-
}
|
|
340
|
-
}
|
|
341
|
-
copyRecursively(tempDir, originalProjectRoot);
|
|
342
|
-
console.log(chalk.cyan(`\n🧹 Cleaning up temp directory...`));
|
|
343
|
-
rmSync(tempDir, {
|
|
344
|
-
recursive: true,
|
|
345
|
-
force: true
|
|
346
|
-
});
|
|
347
|
-
console.log(chalk.green(`\n🎉 Successfully replaced ${filesReplaced} files!`));
|
|
348
|
-
console.log(chalk.gray(` Your project files have been updated with the generated content.`));
|
|
349
|
-
console.log(chalk.gray(` Temp directory cleaned up.`));
|
|
350
|
-
} catch (error) {
|
|
351
|
-
const errorMsg = error instanceof Error ? error.message : String(error);
|
|
352
|
-
console.log(chalk.red(`\n❌ Failed to overwrite project files: ${errorMsg}`));
|
|
353
|
-
console.log(chalk.yellow(` Generated files remain in: ${tempDirName} for manual review`));
|
|
354
|
-
}
|
|
355
|
-
}
|
|
356
|
-
|
|
357
|
-
//#endregion
|
|
358
|
-
export { validateTempDirectory };
|
|
@@ -1,173 +0,0 @@
|
|
|
1
|
-
import { Node, Project } from "ts-morph";
|
|
2
|
-
import { randomBytes } from "node:crypto";
|
|
3
|
-
|
|
4
|
-
//#region src/commands/pull-v3/targeted-typescript-placeholders.ts
|
|
5
|
-
/**
|
|
6
|
-
* Targeted TypeScript Placeholder System
|
|
7
|
-
*
|
|
8
|
-
* Uses AST parsing to intelligently identify large content blocks for replacement:
|
|
9
|
-
* - prompt: (template literals or strings)
|
|
10
|
-
* - description: (string literals)
|
|
11
|
-
* - inputSchema: (object literals)
|
|
12
|
-
* - detailsSchema: (object literals)
|
|
13
|
-
* - props: (object literals in artifact/data components)
|
|
14
|
-
*/
|
|
15
|
-
/**
|
|
16
|
-
* Generate a unique placeholder ID
|
|
17
|
-
*/
|
|
18
|
-
function generatePlaceholderId() {
|
|
19
|
-
return randomBytes(4).toString("hex").toUpperCase();
|
|
20
|
-
}
|
|
21
|
-
/**
|
|
22
|
-
* Minimum length threshold for replacement (only replace if longer than this)
|
|
23
|
-
*/
|
|
24
|
-
const MIN_REPLACEMENT_LENGTH = 10;
|
|
25
|
-
/**
|
|
26
|
-
* Create targeted placeholders using AST parsing for better accuracy
|
|
27
|
-
*/
|
|
28
|
-
function createTargetedTypeScriptPlaceholders(content) {
|
|
29
|
-
const replacements = {};
|
|
30
|
-
let replacedFields = 0;
|
|
31
|
-
const originalSize = content.length;
|
|
32
|
-
try {
|
|
33
|
-
const sourceFile = new Project({ useInMemoryFileSystem: true }).createSourceFile("temp.ts", content);
|
|
34
|
-
const replacementOperations = [];
|
|
35
|
-
sourceFile.forEachDescendant((node) => {
|
|
36
|
-
if (Node.isPropertyAssignment(node)) {
|
|
37
|
-
const propertyName = node.getName();
|
|
38
|
-
const valueNode = node.getInitializer();
|
|
39
|
-
if (!valueNode) return;
|
|
40
|
-
let valueText = valueNode.getText();
|
|
41
|
-
if (valueText.trim().length < MIN_REPLACEMENT_LENGTH) return;
|
|
42
|
-
let placeholderPrefix = "";
|
|
43
|
-
switch (propertyName) {
|
|
44
|
-
case "prompt":
|
|
45
|
-
placeholderPrefix = "PROMPT";
|
|
46
|
-
break;
|
|
47
|
-
case "description":
|
|
48
|
-
placeholderPrefix = "DESC";
|
|
49
|
-
break;
|
|
50
|
-
case "inputSchema":
|
|
51
|
-
placeholderPrefix = "INPUT_SCHEMA";
|
|
52
|
-
break;
|
|
53
|
-
case "detailsSchema":
|
|
54
|
-
placeholderPrefix = "DETAILS_SCHEMA";
|
|
55
|
-
break;
|
|
56
|
-
case "props":
|
|
57
|
-
placeholderPrefix = "PROPS";
|
|
58
|
-
break;
|
|
59
|
-
case "render":
|
|
60
|
-
placeholderPrefix = "RENDER";
|
|
61
|
-
break;
|
|
62
|
-
default: return;
|
|
63
|
-
}
|
|
64
|
-
const start = valueNode.getStart();
|
|
65
|
-
let end = valueNode.getEnd();
|
|
66
|
-
const propertyEnd = node.getEnd();
|
|
67
|
-
if (propertyName === "inputSchema" || propertyName === "render") {
|
|
68
|
-
const searchStart = start;
|
|
69
|
-
let braceCount = 0;
|
|
70
|
-
let correctEnd = -1;
|
|
71
|
-
let inString = false;
|
|
72
|
-
let stringChar = "";
|
|
73
|
-
for (let i = searchStart; i < content.length; i++) {
|
|
74
|
-
const char = content[i];
|
|
75
|
-
const prevChar = i > 0 ? content[i - 1] : "";
|
|
76
|
-
if ((char === "\"" || char === "'") && prevChar !== "\\") {
|
|
77
|
-
if (!inString) {
|
|
78
|
-
inString = true;
|
|
79
|
-
stringChar = char;
|
|
80
|
-
} else if (char === stringChar) {
|
|
81
|
-
inString = false;
|
|
82
|
-
stringChar = "";
|
|
83
|
-
}
|
|
84
|
-
}
|
|
85
|
-
if (!inString) {
|
|
86
|
-
if (char === "{") braceCount++;
|
|
87
|
-
else if (char === "}") {
|
|
88
|
-
braceCount--;
|
|
89
|
-
if (braceCount === 0) {
|
|
90
|
-
let j = i + 1;
|
|
91
|
-
while (j < content.length && /\s/.test(content[j])) j++;
|
|
92
|
-
if (j < content.length && content[j] === ",") {
|
|
93
|
-
correctEnd = j + 1;
|
|
94
|
-
break;
|
|
95
|
-
}
|
|
96
|
-
}
|
|
97
|
-
}
|
|
98
|
-
}
|
|
99
|
-
}
|
|
100
|
-
if (correctEnd > start && correctEnd < end + 100) {
|
|
101
|
-
end = correctEnd;
|
|
102
|
-
valueText = content.slice(start, end);
|
|
103
|
-
}
|
|
104
|
-
} else if (!content.slice(end, end + 20).match(/^\s*[,}]/)) {
|
|
105
|
-
let correctEnd = end;
|
|
106
|
-
while (correctEnd > start && !content.slice(correctEnd, correctEnd + 10).match(/^\s*[,}]/)) correctEnd--;
|
|
107
|
-
if (correctEnd > start) {
|
|
108
|
-
end = correctEnd;
|
|
109
|
-
valueText = content.slice(start, end);
|
|
110
|
-
} else return;
|
|
111
|
-
}
|
|
112
|
-
if (end > propertyEnd) return;
|
|
113
|
-
const actualText = content.slice(start, end);
|
|
114
|
-
if (valueText !== actualText) return;
|
|
115
|
-
if (!content.slice(end, end + 20).match(/^\s*[,}]/)) return;
|
|
116
|
-
const placeholder = `<${placeholderPrefix}_${generatePlaceholderId()}>`;
|
|
117
|
-
replacements[placeholder] = valueText;
|
|
118
|
-
replacedFields++;
|
|
119
|
-
replacementOperations.push({
|
|
120
|
-
start,
|
|
121
|
-
end,
|
|
122
|
-
placeholder,
|
|
123
|
-
originalText: valueText
|
|
124
|
-
});
|
|
125
|
-
}
|
|
126
|
-
});
|
|
127
|
-
replacementOperations.sort((a, b) => b.start - a.start);
|
|
128
|
-
let processedContent = content;
|
|
129
|
-
for (const op of replacementOperations) processedContent = processedContent.slice(0, op.start) + op.placeholder + processedContent.slice(op.end);
|
|
130
|
-
const processedSize = processedContent.length;
|
|
131
|
-
const savings = originalSize - processedSize;
|
|
132
|
-
const savingsPercentage = originalSize > 0 ? savings / originalSize * 100 : 0;
|
|
133
|
-
return {
|
|
134
|
-
processedContent,
|
|
135
|
-
replacements,
|
|
136
|
-
stats: {
|
|
137
|
-
originalSize,
|
|
138
|
-
processedSize,
|
|
139
|
-
savings,
|
|
140
|
-
savingsPercentage,
|
|
141
|
-
replacedFields
|
|
142
|
-
}
|
|
143
|
-
};
|
|
144
|
-
} catch {
|
|
145
|
-
return {
|
|
146
|
-
processedContent: content,
|
|
147
|
-
replacements: {},
|
|
148
|
-
stats: {
|
|
149
|
-
originalSize,
|
|
150
|
-
processedSize: originalSize,
|
|
151
|
-
savings: 0,
|
|
152
|
-
savingsPercentage: 0,
|
|
153
|
-
replacedFields: 0
|
|
154
|
-
}
|
|
155
|
-
};
|
|
156
|
-
}
|
|
157
|
-
}
|
|
158
|
-
/**
|
|
159
|
-
* Restore placeholders in TypeScript content
|
|
160
|
-
*/
|
|
161
|
-
function restoreTargetedTypeScriptPlaceholders(content, replacements) {
|
|
162
|
-
let restoredContent = content;
|
|
163
|
-
const sortedPlaceholders = Object.keys(replacements).sort((a, b) => b.length - a.length);
|
|
164
|
-
for (const placeholder of sortedPlaceholders) {
|
|
165
|
-
const originalValue = replacements[placeholder];
|
|
166
|
-
if (!restoredContent.includes(placeholder)) continue;
|
|
167
|
-
restoredContent = restoredContent.replace(placeholder, originalValue);
|
|
168
|
-
}
|
|
169
|
-
return restoredContent;
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
//#endregion
|
|
173
|
-
export { createTargetedTypeScriptPlaceholders, restoreTargetedTypeScriptPlaceholders };
|