@inkeep/agents-cli 0.39.5 → 0.41.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/_virtual/rolldown_runtime.js +7 -0
- package/dist/api.js +185 -0
- package/dist/commands/add.js +139 -0
- package/dist/commands/config.js +86 -0
- package/dist/commands/dev.js +259 -0
- package/dist/commands/init.js +360 -0
- package/dist/commands/list-agents.js +56 -0
- package/dist/commands/login.js +179 -0
- package/dist/commands/logout.js +56 -0
- package/dist/commands/profile.js +276 -0
- package/dist/{component-parser2.js → commands/pull-v3/component-parser.js} +16 -3
- package/dist/commands/pull-v3/component-updater.js +710 -0
- package/dist/commands/pull-v3/components/agent-generator.js +241 -0
- package/dist/commands/pull-v3/components/artifact-component-generator.js +143 -0
- package/dist/commands/pull-v3/components/context-config-generator.js +190 -0
- package/dist/commands/pull-v3/components/credential-generator.js +89 -0
- package/dist/commands/pull-v3/components/data-component-generator.js +102 -0
- package/dist/commands/pull-v3/components/environment-generator.js +170 -0
- package/dist/commands/pull-v3/components/external-agent-generator.js +75 -0
- package/dist/commands/pull-v3/components/function-tool-generator.js +94 -0
- package/dist/commands/pull-v3/components/mcp-tool-generator.js +86 -0
- package/dist/commands/pull-v3/components/project-generator.js +145 -0
- package/dist/commands/pull-v3/components/status-component-generator.js +92 -0
- package/dist/commands/pull-v3/components/sub-agent-generator.js +285 -0
- package/dist/commands/pull-v3/index.js +510 -0
- package/dist/commands/pull-v3/introspect-generator.js +278 -0
- package/dist/commands/pull-v3/llm-content-merger.js +192 -0
- package/dist/{new-component-generator.js → commands/pull-v3/new-component-generator.js} +14 -3
- package/dist/commands/pull-v3/project-comparator.js +914 -0
- package/dist/{project-index-generator.js → commands/pull-v3/project-index-generator.js} +1 -2
- package/dist/{project-validator.js → commands/pull-v3/project-validator.js} +4 -4
- package/dist/commands/pull-v3/targeted-typescript-placeholders.js +173 -0
- package/dist/commands/pull-v3/utils/component-registry.js +369 -0
- package/dist/commands/pull-v3/utils/component-tracker.js +165 -0
- package/dist/commands/pull-v3/utils/generator-utils.js +146 -0
- package/dist/commands/pull-v3/utils/model-provider-detector.js +44 -0
- package/dist/commands/push.js +326 -0
- package/dist/commands/status.js +89 -0
- package/dist/commands/update.js +97 -0
- package/dist/commands/whoami.js +38 -0
- package/dist/config.js +0 -1
- package/dist/env.js +30 -0
- package/dist/exports.js +3 -0
- package/dist/index.js +28 -196514
- package/dist/instrumentation.js +47 -0
- package/dist/types/agent.js +1 -0
- package/dist/types/tsx.d.d.ts +1 -0
- package/dist/utils/background-version-check.js +19 -0
- package/dist/utils/ci-environment.js +87 -0
- package/dist/utils/cli-pipeline.js +158 -0
- package/dist/utils/config.js +290 -0
- package/dist/utils/credentials.js +132 -0
- package/dist/utils/environment-loader.js +28 -0
- package/dist/utils/file-finder.js +62 -0
- package/dist/utils/json-comparator.js +185 -0
- package/dist/utils/json-comparison.js +232 -0
- package/dist/utils/mcp-runner.js +120 -0
- package/dist/utils/model-config.js +182 -0
- package/dist/utils/package-manager.js +58 -0
- package/dist/utils/profile-config.js +85 -0
- package/dist/utils/profiles/index.js +4 -0
- package/dist/utils/profiles/profile-manager.js +219 -0
- package/dist/utils/profiles/types.js +62 -0
- package/dist/utils/project-directory.js +33 -0
- package/dist/utils/project-loader.js +29 -0
- package/dist/utils/schema-introspection.js +44 -0
- package/dist/utils/templates.js +198 -0
- package/dist/utils/tsx-loader.js +27 -0
- package/dist/utils/url.js +26 -0
- package/dist/utils/version-check.js +79 -0
- package/package.json +9 -24
- package/dist/component-parser.js +0 -4
- package/dist/component-updater.js +0 -4
- package/dist/config2.js +0 -4
- package/dist/credential-stores.js +0 -4
- package/dist/environment-generator.js +0 -4
- package/dist/nodefs.js +0 -27
- package/dist/opfs-ahp.js +0 -368
- package/dist/project-loader.js +0 -4
- package/dist/tsx-loader.js +0 -4
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
|
|
3
|
+
//#region src/utils/profiles/types.ts
|
|
4
|
+
/**
|
|
5
|
+
* Baked-in URLs for Inkeep Cloud deployment
|
|
6
|
+
*/
|
|
7
|
+
const CLOUD_REMOTE = {
|
|
8
|
+
manageApi: "https://manage-api.inkeep.com",
|
|
9
|
+
manageUi: "https://manage.inkeep.com",
|
|
10
|
+
runApi: "https://run-api.inkeep.com"
|
|
11
|
+
};
|
|
12
|
+
/**
|
|
13
|
+
* Schema for explicit remote URLs (custom/local deployments)
|
|
14
|
+
*/
|
|
15
|
+
const explicitRemoteSchema = z.object({
|
|
16
|
+
manageApi: z.string().url("manageApi must be a valid URL"),
|
|
17
|
+
manageUi: z.string().url("manageUi must be a valid URL"),
|
|
18
|
+
runApi: z.string().url("runApi must be a valid URL")
|
|
19
|
+
});
|
|
20
|
+
/**
|
|
21
|
+
* Schema for remote configuration - either 'cloud' shorthand or explicit URLs
|
|
22
|
+
*/
|
|
23
|
+
const remoteSchema = z.union([z.literal("cloud"), explicitRemoteSchema]);
|
|
24
|
+
/**
|
|
25
|
+
* Profile name validation - alphanumeric + hyphens only
|
|
26
|
+
*/
|
|
27
|
+
const profileNameSchema = z.string().min(1, "Profile name cannot be empty").max(64, "Profile name too long (max 64 characters)").regex(/^[a-z0-9-]+$/, "Profile name must be lowercase alphanumeric with hyphens only");
|
|
28
|
+
/**
|
|
29
|
+
* Schema for a single profile configuration
|
|
30
|
+
*/
|
|
31
|
+
const profileSchema = z.object({
|
|
32
|
+
remote: remoteSchema,
|
|
33
|
+
credential: z.string().min(1, "Credential reference cannot be empty"),
|
|
34
|
+
environment: z.string().min(1, "Environment cannot be empty")
|
|
35
|
+
});
|
|
36
|
+
/**
|
|
37
|
+
* Schema for the entire profiles.yaml configuration
|
|
38
|
+
* Note: We use z.record(z.string(), profileSchema) for Zod v4 compatibility
|
|
39
|
+
* Profile name validation is done separately in addProfile
|
|
40
|
+
*/
|
|
41
|
+
const profilesConfigSchema = z.object({
|
|
42
|
+
activeProfile: z.string().min(1, "activeProfile cannot be empty"),
|
|
43
|
+
profiles: z.record(z.string(), profileSchema)
|
|
44
|
+
});
|
|
45
|
+
/**
|
|
46
|
+
* Default cloud profile configuration
|
|
47
|
+
*/
|
|
48
|
+
const DEFAULT_CLOUD_PROFILE = {
|
|
49
|
+
remote: "cloud",
|
|
50
|
+
credential: "inkeep-cloud",
|
|
51
|
+
environment: "production"
|
|
52
|
+
};
|
|
53
|
+
/**
|
|
54
|
+
* Default profiles.yaml content when creating for the first time
|
|
55
|
+
*/
|
|
56
|
+
const DEFAULT_PROFILES_CONFIG = {
|
|
57
|
+
activeProfile: "cloud",
|
|
58
|
+
profiles: { cloud: DEFAULT_CLOUD_PROFILE }
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
//#endregion
|
|
62
|
+
export { CLOUD_REMOTE, DEFAULT_CLOUD_PROFILE, DEFAULT_PROFILES_CONFIG, explicitRemoteSchema, profileNameSchema, profileSchema, profilesConfigSchema, remoteSchema };
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { existsSync } from "node:fs";
|
|
2
|
+
import { join, resolve } from "node:path";
|
|
3
|
+
import { findUp } from "find-up";
|
|
4
|
+
|
|
5
|
+
//#region src/utils/project-directory.ts
|
|
6
|
+
/**
|
|
7
|
+
* Find project directory by looking for inkeep.config.ts
|
|
8
|
+
* @param projectId - Optional project ID or path to look for
|
|
9
|
+
* @param configPath - Optional specific config file path to use
|
|
10
|
+
* @returns Path to project directory or null if not found
|
|
11
|
+
*/
|
|
12
|
+
async function findProjectDirectory(projectId, configPath) {
|
|
13
|
+
if (configPath) {
|
|
14
|
+
const absoluteConfigPath = resolve(process.cwd(), configPath);
|
|
15
|
+
if (existsSync(absoluteConfigPath)) return resolve(absoluteConfigPath, "..");
|
|
16
|
+
}
|
|
17
|
+
if (projectId) {
|
|
18
|
+
if (projectId.includes("/") || projectId.includes("\\")) {
|
|
19
|
+
const projectPath = resolve(process.cwd(), projectId);
|
|
20
|
+
if (existsSync(join(projectPath, "inkeep.config.ts"))) return projectPath;
|
|
21
|
+
} else {
|
|
22
|
+
const projectPath = join(process.cwd(), projectId);
|
|
23
|
+
if (existsSync(join(projectPath, "inkeep.config.ts"))) return projectPath;
|
|
24
|
+
}
|
|
25
|
+
return null;
|
|
26
|
+
}
|
|
27
|
+
const foundConfigPath = await findUp("inkeep.config.ts");
|
|
28
|
+
if (foundConfigPath) return resolve(foundConfigPath, "..");
|
|
29
|
+
return null;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
//#endregion
|
|
33
|
+
export { findProjectDirectory };
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { importWithTypeScriptSupport } from "./tsx-loader.js";
|
|
2
|
+
import { existsSync } from "node:fs";
|
|
3
|
+
import { join } from "node:path";
|
|
4
|
+
|
|
5
|
+
//#region src/utils/project-loader.ts
|
|
6
|
+
/**
|
|
7
|
+
* Load and validate project from index.ts
|
|
8
|
+
*
|
|
9
|
+
* This utility is shared between push and pull commands to ensure
|
|
10
|
+
* consistent project loading behavior across the CLI.
|
|
11
|
+
*
|
|
12
|
+
* @param projectDir - The directory containing the index.ts file
|
|
13
|
+
* @returns The loaded Project instance
|
|
14
|
+
* @throws Error if index.ts not found or no valid project export found
|
|
15
|
+
*/
|
|
16
|
+
async function loadProject(projectDir) {
|
|
17
|
+
const indexPath = join(projectDir, "index.ts");
|
|
18
|
+
if (!existsSync(indexPath)) throw new Error(`index.ts not found in project directory: ${projectDir}`);
|
|
19
|
+
const module = await importWithTypeScriptSupport(indexPath);
|
|
20
|
+
const exports = Object.keys(module);
|
|
21
|
+
for (const exportKey of exports) {
|
|
22
|
+
const value = module[exportKey];
|
|
23
|
+
if (value && typeof value === "object" && value.__type === "project") return value;
|
|
24
|
+
}
|
|
25
|
+
throw new Error("No project export found in index.ts. Expected an export with __type = \"project\"");
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
//#endregion
|
|
29
|
+
export { loadProject };
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
|
|
3
|
+
//#region src/utils/schema-introspection.ts
|
|
4
|
+
/**
|
|
5
|
+
* Schema Introspection Utilities
|
|
6
|
+
*
|
|
7
|
+
* Utilities to extract required fields and other metadata from Zod schemas.
|
|
8
|
+
* This ensures CLI generators stay in sync with the actual validation schemas.
|
|
9
|
+
*/
|
|
10
|
+
/**
|
|
11
|
+
* Simple utility to get required fields by attempting validation with empty object
|
|
12
|
+
* and analyzing which fields are reported as missing
|
|
13
|
+
*/
|
|
14
|
+
function getRequiredFieldsFromValidation(schema) {
|
|
15
|
+
try {
|
|
16
|
+
schema.parse({});
|
|
17
|
+
return [];
|
|
18
|
+
} catch (error) {
|
|
19
|
+
if (error instanceof z.ZodError) return error.issues.filter((err) => err.code === "invalid_type" && err.expected !== "undefined").map((err) => err.path[0]).filter((field) => typeof field === "string").filter((field, index, arr) => arr.indexOf(field) === index);
|
|
20
|
+
return [];
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Extract required field names from a Zod object schema
|
|
25
|
+
*/
|
|
26
|
+
function getRequiredFields(schema) {
|
|
27
|
+
return getRequiredFieldsFromValidation(schema);
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Get a human-readable summary of schema requirements
|
|
31
|
+
*/
|
|
32
|
+
function getSchemaInfo(schema) {
|
|
33
|
+
const requiredFields = getRequiredFields(schema);
|
|
34
|
+
let allFields = [];
|
|
35
|
+
if ("shape" in schema && schema.shape) allFields = Object.keys(schema.shape);
|
|
36
|
+
return {
|
|
37
|
+
requiredFields,
|
|
38
|
+
optionalFields: allFields.filter((field) => !requiredFields.includes(field)),
|
|
39
|
+
allFields
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
//#endregion
|
|
44
|
+
export { getRequiredFields, getSchemaInfo };
|
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
import { getLogger } from "@inkeep/agents-core";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import fs from "fs-extra";
|
|
4
|
+
import degit from "degit";
|
|
5
|
+
|
|
6
|
+
//#region src/utils/templates.ts
|
|
7
|
+
getLogger("templates");
|
|
8
|
+
async function cloneTemplate(templatePath, targetPath, replacements) {
|
|
9
|
+
await fs.mkdir(targetPath, { recursive: true });
|
|
10
|
+
const emitter = degit(templatePath.replace("https://github.com/", ""));
|
|
11
|
+
try {
|
|
12
|
+
await emitter.clone(targetPath);
|
|
13
|
+
if (replacements && replacements.length > 0) await replaceContentInFiles(targetPath, replacements);
|
|
14
|
+
} catch (_error) {
|
|
15
|
+
console.log(`❌ Error cloning template: ${_error}`);
|
|
16
|
+
process.exit(1);
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
async function cloneTemplateLocal(templatePath, targetPath, replacements) {
|
|
20
|
+
await fs.mkdir(targetPath, { recursive: true });
|
|
21
|
+
try {
|
|
22
|
+
await fs.copy(templatePath, targetPath, {
|
|
23
|
+
overwrite: true,
|
|
24
|
+
errorOnExist: false
|
|
25
|
+
});
|
|
26
|
+
if (replacements && replacements.length > 0) await replaceContentInFiles(targetPath, replacements);
|
|
27
|
+
} catch (error) {
|
|
28
|
+
console.error(`Failed to clone template from ${templatePath}:`, error);
|
|
29
|
+
process.exit(1);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Replace content in cloned template files
|
|
34
|
+
*/
|
|
35
|
+
async function replaceContentInFiles(targetPath, replacements) {
|
|
36
|
+
for (const replacement of replacements) {
|
|
37
|
+
const filePath = path.join(targetPath, replacement.filePath);
|
|
38
|
+
if (!await fs.pathExists(filePath)) {
|
|
39
|
+
console.warn(`Warning: File ${filePath} not found, skipping replacements`);
|
|
40
|
+
continue;
|
|
41
|
+
}
|
|
42
|
+
const updatedContent = await replaceObjectProperties(await fs.readFile(filePath, "utf-8"), replacement.replacements);
|
|
43
|
+
await fs.writeFile(filePath, updatedContent, "utf-8");
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Replace object properties in TypeScript code content
|
|
48
|
+
*/
|
|
49
|
+
async function replaceObjectProperties(content, replacements) {
|
|
50
|
+
let updatedContent = content;
|
|
51
|
+
for (const [propertyPath, replacement] of Object.entries(replacements)) updatedContent = replaceObjectProperty(updatedContent, propertyPath, replacement);
|
|
52
|
+
return updatedContent;
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Replace a specific object property in TypeScript code
|
|
56
|
+
* This implementation uses line-by-line parsing for better accuracy
|
|
57
|
+
* If the property doesn't exist, it will be added to the object
|
|
58
|
+
*/
|
|
59
|
+
function replaceObjectProperty(content, propertyPath, replacement) {
|
|
60
|
+
if (content.match(new RegExp(`^(.+{[^{}]*${propertyPath}\\s*:\\s*{[^{}]*}[^{}]*}.*)$`, "m"))) {
|
|
61
|
+
const singleLinePattern = /* @__PURE__ */ new RegExp(`((^|\\s|{)${propertyPath}\\s*:\\s*)({[^}]*})`);
|
|
62
|
+
return content.replace(singleLinePattern, `$1${JSON.stringify(replacement).replace(/"/g, "'").replace(/:/g, ": ").replace(/,/g, ", ")}`);
|
|
63
|
+
}
|
|
64
|
+
const replacementStr = JSON.stringify(replacement, null, 2).replace(/"/g, "'");
|
|
65
|
+
const lines = content.split("\n");
|
|
66
|
+
const result = [];
|
|
67
|
+
let inTargetProperty = false;
|
|
68
|
+
let braceCount = 0;
|
|
69
|
+
let targetPropertyIndent = "";
|
|
70
|
+
let foundProperty = false;
|
|
71
|
+
for (let i = 0; i < lines.length; i++) {
|
|
72
|
+
const line = lines[i];
|
|
73
|
+
const trimmedLine = line.trim();
|
|
74
|
+
if (inTargetProperty) {
|
|
75
|
+
for (const char of line) {
|
|
76
|
+
if (char === "{") braceCount++;
|
|
77
|
+
if (char === "}") braceCount--;
|
|
78
|
+
}
|
|
79
|
+
if (braceCount <= 0) {
|
|
80
|
+
const hasTrailingComma = line.includes(",") || i + 1 < lines.length && lines[i + 1].trim().startsWith("}") === false && lines[i + 1].trim() !== "";
|
|
81
|
+
const indentedReplacement = replacementStr.split("\n").map((replacementLine, index) => {
|
|
82
|
+
if (index === 0) return `${targetPropertyIndent}${propertyPath}: ${replacementLine}`;
|
|
83
|
+
return `${targetPropertyIndent}${replacementLine}`;
|
|
84
|
+
}).join("\n");
|
|
85
|
+
result.push(`${indentedReplacement}${hasTrailingComma ? "," : ""}`);
|
|
86
|
+
inTargetProperty = false;
|
|
87
|
+
foundProperty = true;
|
|
88
|
+
continue;
|
|
89
|
+
}
|
|
90
|
+
continue;
|
|
91
|
+
}
|
|
92
|
+
const propertyPattern = /* @__PURE__ */ new RegExp(`(^|\\s+)${propertyPath}\\s*:`);
|
|
93
|
+
if (trimmedLine.startsWith(`${propertyPath}:`) || propertyPattern.test(line)) {
|
|
94
|
+
inTargetProperty = true;
|
|
95
|
+
braceCount = 0;
|
|
96
|
+
if (line.includes(" = { ")) targetPropertyIndent = `${line.match(/^\s*/)?.[0] || ""} `;
|
|
97
|
+
else {
|
|
98
|
+
const propertyMatch = line.match(/* @__PURE__ */ new RegExp(`(.*?)(^|\\s+)${propertyPath}\\s*:`));
|
|
99
|
+
targetPropertyIndent = propertyMatch ? propertyMatch[1] : line.match(/^\s*/)?.[0] || "";
|
|
100
|
+
}
|
|
101
|
+
for (const char of line) {
|
|
102
|
+
if (char === "{") braceCount++;
|
|
103
|
+
if (char === "}") braceCount--;
|
|
104
|
+
}
|
|
105
|
+
if (braceCount <= 0) {
|
|
106
|
+
const hasTrailingComma = line.includes(",");
|
|
107
|
+
const indentedReplacement = replacementStr.split("\n").map((replacementLine, index) => {
|
|
108
|
+
if (index === 0) return `${targetPropertyIndent}${propertyPath}: ${replacementLine}`;
|
|
109
|
+
return `${targetPropertyIndent}${replacementLine}`;
|
|
110
|
+
}).join("\n");
|
|
111
|
+
result.push(`${indentedReplacement}${hasTrailingComma ? "," : ""}`);
|
|
112
|
+
inTargetProperty = false;
|
|
113
|
+
foundProperty = true;
|
|
114
|
+
continue;
|
|
115
|
+
}
|
|
116
|
+
continue;
|
|
117
|
+
}
|
|
118
|
+
result.push(line);
|
|
119
|
+
}
|
|
120
|
+
if (!foundProperty) return injectPropertyIntoObject(result.join("\n"), propertyPath, replacement);
|
|
121
|
+
return result.join("\n");
|
|
122
|
+
}
|
|
123
|
+
/**
|
|
124
|
+
* Inject a new property into a TypeScript object when the property doesn't exist
|
|
125
|
+
*/
|
|
126
|
+
function injectPropertyIntoObject(content, propertyPath, replacement) {
|
|
127
|
+
const replacementStr = JSON.stringify(replacement, null, 2).replace(/"/g, "'");
|
|
128
|
+
const lines = content.split("\n");
|
|
129
|
+
const result = [];
|
|
130
|
+
let foundObjectStart = false;
|
|
131
|
+
let objectDepth = 0;
|
|
132
|
+
let insertionPoint = -1;
|
|
133
|
+
let baseIndent = "";
|
|
134
|
+
for (let i = 0; i < lines.length; i++) {
|
|
135
|
+
const line = lines[i];
|
|
136
|
+
const trimmedLine = line.trim();
|
|
137
|
+
if (!foundObjectStart && (trimmedLine.includes("({") || trimmedLine.endsWith(" = {") || line.includes(" = { "))) {
|
|
138
|
+
foundObjectStart = true;
|
|
139
|
+
baseIndent = line.match(/^\s*/)?.[0] || "";
|
|
140
|
+
objectDepth = 0;
|
|
141
|
+
for (const char of line) {
|
|
142
|
+
if (char === "{") objectDepth++;
|
|
143
|
+
if (char === "}") objectDepth--;
|
|
144
|
+
}
|
|
145
|
+
} else if (foundObjectStart) {
|
|
146
|
+
for (const char of line) {
|
|
147
|
+
if (char === "{") objectDepth++;
|
|
148
|
+
if (char === "}") objectDepth--;
|
|
149
|
+
}
|
|
150
|
+
if (objectDepth === 0 && trimmedLine.startsWith("}")) {
|
|
151
|
+
insertionPoint = i;
|
|
152
|
+
break;
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
if (insertionPoint !== -1) {
|
|
157
|
+
const propertyIndent = `${baseIndent} `;
|
|
158
|
+
let needsCommaPrefix = false;
|
|
159
|
+
if (insertionPoint > 0) {
|
|
160
|
+
const prevLine = lines[insertionPoint - 1].trim();
|
|
161
|
+
needsCommaPrefix = prevLine !== "" && !prevLine.endsWith(",") && !prevLine.startsWith("}");
|
|
162
|
+
}
|
|
163
|
+
const indentedReplacement = replacementStr.split("\n").map((replacementLine, index) => {
|
|
164
|
+
if (index === 0) return `${propertyIndent}${propertyPath}: ${replacementLine}`;
|
|
165
|
+
return `${propertyIndent}${replacementLine}`;
|
|
166
|
+
}).join("\n");
|
|
167
|
+
for (let i = 0; i < lines.length; i++) {
|
|
168
|
+
if (i === insertionPoint) result.push(indentedReplacement);
|
|
169
|
+
if (i === insertionPoint - 1 && needsCommaPrefix) result.push(`${lines[i]},`);
|
|
170
|
+
else result.push(lines[i]);
|
|
171
|
+
}
|
|
172
|
+
return result.join("\n");
|
|
173
|
+
}
|
|
174
|
+
console.warn(`Could not inject property "${propertyPath}" - no suitable object found in content`);
|
|
175
|
+
return content;
|
|
176
|
+
}
|
|
177
|
+
async function getAvailableTemplates(templatePath = "template-projects", local) {
|
|
178
|
+
if (local && local.length > 0) {
|
|
179
|
+
const fullTemplatePath = path.join(local, templatePath);
|
|
180
|
+
const items = await fs.readdir(fullTemplatePath);
|
|
181
|
+
const directories = [];
|
|
182
|
+
for (const item of items) if ((await fs.stat(path.join(fullTemplatePath, item))).isDirectory() && item !== "weather-project") directories.push(item);
|
|
183
|
+
return directories;
|
|
184
|
+
}
|
|
185
|
+
const response = await fetch(`https://api.github.com/repos/inkeep/agents/contents/agents-cookbook/${templatePath}`);
|
|
186
|
+
if (!response.ok) throw new Error(`Failed to fetch templates. Please check your internet connection and try again.`);
|
|
187
|
+
let contents;
|
|
188
|
+
try {
|
|
189
|
+
contents = await response.json();
|
|
190
|
+
} catch (error) {
|
|
191
|
+
throw new Error(`Failed to parse templates response. Please check your internet connection and try again. ${error}`);
|
|
192
|
+
}
|
|
193
|
+
if (!Array.isArray(contents)) throw new Error("Unexpected response format from templates. Please check your internet connection and try again");
|
|
194
|
+
return contents.filter((item) => item.type === "dir" && item.name !== "weather-project").map((item) => item.name);
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
//#endregion
|
|
198
|
+
export { cloneTemplate, cloneTemplateLocal, getAvailableTemplates, replaceContentInFiles, replaceObjectProperties };
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { extname } from "node:path";
|
|
2
|
+
import { pathToFileURL } from "node:url";
|
|
3
|
+
import { register } from "tsx/esm/api";
|
|
4
|
+
|
|
5
|
+
//#region src/utils/tsx-loader.ts
|
|
6
|
+
/**
|
|
7
|
+
* Dynamically imports a file with TypeScript support
|
|
8
|
+
* Registers tsx loader for .ts files automatically
|
|
9
|
+
*/
|
|
10
|
+
async function importWithTypeScriptSupport(filePath) {
|
|
11
|
+
if (extname(filePath) === ".ts") try {
|
|
12
|
+
const unregister = register();
|
|
13
|
+
try {
|
|
14
|
+
return await import(pathToFileURL(filePath).href);
|
|
15
|
+
} finally {
|
|
16
|
+
unregister();
|
|
17
|
+
}
|
|
18
|
+
} catch (error) {
|
|
19
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
20
|
+
if (errorMessage.includes("Dynamic require") || errorMessage.includes("tsx") || errorMessage.includes("register")) throw new Error(`Failed to load TypeScript file ${filePath}. Make sure tsx is installed: ${errorMessage}`);
|
|
21
|
+
throw error;
|
|
22
|
+
}
|
|
23
|
+
return await import(pathToFileURL(filePath).href);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
//#endregion
|
|
27
|
+
export { importWithTypeScriptSupport };
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
//#region src/utils/url.ts
|
|
2
|
+
/**
|
|
3
|
+
* Normalizes a base URL by removing trailing slashes and validating format
|
|
4
|
+
* @param url The URL to normalize
|
|
5
|
+
* @returns The normalized URL
|
|
6
|
+
* @throws Error if URL is invalid
|
|
7
|
+
*/
|
|
8
|
+
function normalizeBaseUrl(url) {
|
|
9
|
+
const trimmedUrl = url.trim();
|
|
10
|
+
if (!trimmedUrl.match(/^https?:\/\//i)) throw new Error(`Invalid URL format: ${url}. Must start with http:// or https://`);
|
|
11
|
+
return trimmedUrl.replace(/\/+$/, "");
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Constructs an agent view URL for the management UI
|
|
15
|
+
* @param manageUiUrl The base management UI URL
|
|
16
|
+
* @param tenantId The tenant ID
|
|
17
|
+
* @param projectId The project ID
|
|
18
|
+
* @param agentId The agent ID
|
|
19
|
+
* @returns The complete agent view URL
|
|
20
|
+
*/
|
|
21
|
+
function buildAgentViewUrl(manageUiUrl, tenantId, projectId, agentId) {
|
|
22
|
+
return `${normalizeBaseUrl(manageUiUrl || "http://localhost:3000")}/${tenantId}/projects/${projectId}/agents/${agentId}`;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
//#endregion
|
|
26
|
+
export { buildAgentViewUrl, normalizeBaseUrl };
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import { existsSync, readFileSync } from "node:fs";
|
|
2
|
+
import { dirname, join } from "node:path";
|
|
3
|
+
import { fileURLToPath } from "node:url";
|
|
4
|
+
|
|
5
|
+
//#region src/utils/version-check.ts
|
|
6
|
+
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
7
|
+
/**
|
|
8
|
+
* The default package name for version checks and updates
|
|
9
|
+
*/
|
|
10
|
+
const DEFAULT_PACKAGE_NAME = "@inkeep/agents-cli";
|
|
11
|
+
/**
|
|
12
|
+
* Get the current installed version from package.json
|
|
13
|
+
*/
|
|
14
|
+
function getCurrentVersion() {
|
|
15
|
+
let packageJsonPath = join(__dirname, "..", "package.json");
|
|
16
|
+
if (!existsSync(packageJsonPath)) packageJsonPath = join(__dirname, "..", "..", "package.json");
|
|
17
|
+
return JSON.parse(readFileSync(packageJsonPath, "utf-8")).version;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Fetch the latest version from npm registry
|
|
21
|
+
*/
|
|
22
|
+
async function getLatestVersion(packageName = DEFAULT_PACKAGE_NAME) {
|
|
23
|
+
const controller = new AbortController();
|
|
24
|
+
const timeoutId = setTimeout(() => controller.abort(), 1e4);
|
|
25
|
+
try {
|
|
26
|
+
const response = await fetch(`https://registry.npmjs.org/${packageName}/latest`, { signal: controller.signal });
|
|
27
|
+
if (!response.ok) throw new Error(`Failed to fetch latest version: ${response.statusText}`);
|
|
28
|
+
return (await response.json()).version;
|
|
29
|
+
} catch (error) {
|
|
30
|
+
if (error instanceof Error && error.name === "AbortError") throw new Error("Unable to check for updates: Request timed out after 10 seconds");
|
|
31
|
+
throw new Error(`Unable to check for updates: ${error instanceof Error ? error.message : "Unknown error"}`);
|
|
32
|
+
} finally {
|
|
33
|
+
clearTimeout(timeoutId);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Compare two semver versions
|
|
38
|
+
* Returns: -1 if v1 < v2, 0 if v1 === v2, 1 if v1 > v2
|
|
39
|
+
*
|
|
40
|
+
* Note: This is a simplified semver comparison that handles basic major.minor.patch versions.
|
|
41
|
+
* It does NOT handle pre-release versions (e.g., 1.0.0-beta.1) or build metadata (e.g., 1.0.0+build.1).
|
|
42
|
+
* Pre-release tags and build metadata will be stripped before comparison.
|
|
43
|
+
*
|
|
44
|
+
* For the Inkeep CLI use case, this is sufficient as we only publish stable releases.
|
|
45
|
+
*/
|
|
46
|
+
function compareVersions(v1, v2) {
|
|
47
|
+
const cleanV1 = v1.split("-")[0].split("+")[0];
|
|
48
|
+
const cleanV2 = v2.split("-")[0].split("+")[0];
|
|
49
|
+
const parts1 = cleanV1.split(".").map(Number);
|
|
50
|
+
const parts2 = cleanV2.split(".").map(Number);
|
|
51
|
+
for (let i = 0; i < Math.max(parts1.length, parts2.length); i++) {
|
|
52
|
+
const part1 = parts1[i] || 0;
|
|
53
|
+
const part2 = parts2[i] || 0;
|
|
54
|
+
if (part1 < part2) return -1;
|
|
55
|
+
if (part1 > part2) return 1;
|
|
56
|
+
}
|
|
57
|
+
return 0;
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Check if an update is available
|
|
61
|
+
*/
|
|
62
|
+
async function checkForUpdate() {
|
|
63
|
+
const current = getCurrentVersion();
|
|
64
|
+
const latest = await getLatestVersion();
|
|
65
|
+
return {
|
|
66
|
+
current,
|
|
67
|
+
latest,
|
|
68
|
+
needsUpdate: compareVersions(current, latest) < 0
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Get the changelog URL for the package
|
|
73
|
+
*/
|
|
74
|
+
function getChangelogUrl() {
|
|
75
|
+
return `https://github.com/inkeep/agents/blob/main/agents-cli/CHANGELOG.md`;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
//#endregion
|
|
79
|
+
export { DEFAULT_PACKAGE_NAME, checkForUpdate, compareVersions, getChangelogUrl, getCurrentVersion, getLatestVersion };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@inkeep/agents-cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.41.0",
|
|
4
4
|
"description": "Inkeep CLI tool",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -20,50 +20,34 @@
|
|
|
20
20
|
"author": "Inkeep <support@inkeep.com>",
|
|
21
21
|
"license": "SEE LICENSE IN LICENSE.md",
|
|
22
22
|
"dependencies": {
|
|
23
|
-
"@ai-sdk/anthropic": "3.0.
|
|
24
|
-
"@ai-sdk/google": "3.0.
|
|
25
|
-
"@ai-sdk/openai": "3.0.
|
|
26
|
-
"@babel/parser": "^7.23.0",
|
|
27
|
-
"@babel/types": "^7.23.0",
|
|
28
|
-
"@better-auth/sso": "^1.4.0",
|
|
23
|
+
"@ai-sdk/anthropic": "3.0.7",
|
|
24
|
+
"@ai-sdk/google": "3.0.4",
|
|
25
|
+
"@ai-sdk/openai": "3.0.7",
|
|
29
26
|
"@clack/prompts": "^0.11.0",
|
|
30
|
-
"@nangohq/node": "^0.69.14",
|
|
31
|
-
"@opentelemetry/api-logs": "^0.206.0",
|
|
32
|
-
"@opentelemetry/instrumentation": "^0.206.0",
|
|
33
|
-
"@opentelemetry/sdk-logs": "^0.206.0",
|
|
34
27
|
"@vercel/otel": "^2.0.1",
|
|
35
|
-
"ai": "6.0.
|
|
36
|
-
"ast-types": "^0.14.2",
|
|
28
|
+
"ai": "6.0.14",
|
|
37
29
|
"chalk": "^5.3.0",
|
|
38
30
|
"cli-table3": "^0.6.3",
|
|
39
31
|
"commander": "^14.0.0",
|
|
40
32
|
"degit": "^2.8.4",
|
|
41
|
-
"destr": "^2.0.3",
|
|
42
33
|
"dotenv": "^17.2.1",
|
|
43
|
-
"drizzle-orm": "^0.44.5",
|
|
44
34
|
"find-up": "^7.0.0",
|
|
45
35
|
"fs-extra": "^11.2.0",
|
|
46
36
|
"json-schema-to-zod": "^2.6.1",
|
|
47
37
|
"keytar": "^7.9.0",
|
|
48
38
|
"langfuse-vercel": "^3.38.6",
|
|
49
|
-
"
|
|
50
|
-
"pg": "^8.16.3",
|
|
51
|
-
"pino": "^9.11.0",
|
|
52
|
-
"recast": "^0.23.0",
|
|
53
|
-
"traverse": "^0.6.10",
|
|
39
|
+
"open": "^10.2.0",
|
|
54
40
|
"ts-morph": "^26.0.0",
|
|
55
41
|
"tsx": "^4.20.5",
|
|
56
|
-
"open": "^10.2.0",
|
|
57
42
|
"yaml": "^2.7.0",
|
|
58
|
-
"@inkeep/agents-core": "^0.
|
|
59
|
-
"@inkeep/agents-sdk": "^0.
|
|
43
|
+
"@inkeep/agents-core": "^0.41.0",
|
|
44
|
+
"@inkeep/agents-sdk": "^0.41.0"
|
|
60
45
|
},
|
|
61
46
|
"devDependencies": {
|
|
62
47
|
"@types/degit": "^2.8.6",
|
|
63
48
|
"@types/fs-extra": "^11.0.4",
|
|
64
49
|
"@types/node": "^20.10.0",
|
|
65
50
|
"@vitest/coverage-v8": "^3.2.4",
|
|
66
|
-
"pino-pretty": "^13.1.1",
|
|
67
51
|
"tsdown": "^0.18.0",
|
|
68
52
|
"typescript": "^5.9.2",
|
|
69
53
|
"vitest": "^3.2.4"
|
|
@@ -88,6 +72,7 @@
|
|
|
88
72
|
"directory": "agents-cli"
|
|
89
73
|
},
|
|
90
74
|
"scripts": {
|
|
75
|
+
"knip": "knip --directory .. --workspace agents-cli --dependencies",
|
|
91
76
|
"build": "tsdown",
|
|
92
77
|
"cli": "node ./dist/index.js",
|
|
93
78
|
"postinstall": "node scripts/ensure-keytar.mjs || true",
|
package/dist/component-parser.js
DELETED
package/dist/config2.js
DELETED
|
@@ -1,4 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
import { _ as generateEnvironmentIndexFile, b as generateEnvironmentSettingsFile, g as generateEnvironmentIndexDefinition, h as generateEnvironmentFile, v as generateEnvironmentIndexImports, x as generateEnvironmentSettingsImports, y as generateEnvironmentSettingsDefinition } from "./index.js";
|
|
3
|
-
|
|
4
|
-
export { generateEnvironmentIndexFile };
|
package/dist/nodefs.js
DELETED
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
import { B as ur, G as u, L as C } from "./index.js";
|
|
3
|
-
import * as s from "fs";
|
|
4
|
-
import * as o from "path";
|
|
5
|
-
|
|
6
|
-
//#region ../node_modules/.pnpm/@electric-sql+pglite@0.3.14/node_modules/@electric-sql/pglite/dist/fs/nodefs.js
|
|
7
|
-
u();
|
|
8
|
-
var m = class extends ur {
|
|
9
|
-
constructor(t) {
|
|
10
|
-
super(t), this.rootDir = o.resolve(t), s.existsSync(o.join(this.rootDir)) || s.mkdirSync(this.rootDir);
|
|
11
|
-
}
|
|
12
|
-
async init(t, e) {
|
|
13
|
-
return this.pg = t, { emscriptenOpts: {
|
|
14
|
-
...e,
|
|
15
|
-
preRun: [...e.preRun || [], (r) => {
|
|
16
|
-
let c = r.FS.filesystems.NODEFS;
|
|
17
|
-
r.FS.mkdir(C), r.FS.mount(c, { root: this.rootDir }, C);
|
|
18
|
-
}]
|
|
19
|
-
} };
|
|
20
|
-
}
|
|
21
|
-
async closeFs() {
|
|
22
|
-
this.pg.Module.FS.quit();
|
|
23
|
-
}
|
|
24
|
-
};
|
|
25
|
-
|
|
26
|
-
//#endregion
|
|
27
|
-
export { m as NodeFS };
|