@inkeep/agents-cli 0.0.0-dev-20260212002106 → 0.0.0-dev-20260212005842

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/api.js CHANGED
@@ -141,6 +141,66 @@ var ManagementApiClient = class ManagementApiClient extends BaseApiClient {
141
141
  }
142
142
  return allProjects;
143
143
  }
144
+ async getDataComponent(componentId) {
145
+ const tenantId = this.checkTenantId();
146
+ const projectId = this.getProjectId();
147
+ const response = await this.authenticatedFetch(`${this.apiUrl}/manage/tenants/${tenantId}/projects/${projectId}/data-components/${componentId}`, { method: "GET" });
148
+ if (response.status === 404) return null;
149
+ if (!response.ok) {
150
+ const err = await response.text().catch(() => "");
151
+ throw new Error(`Failed to fetch data component: ${response.statusText}${err ? `\n${err}` : ""}`);
152
+ }
153
+ return (await response.json()).data ?? null;
154
+ }
155
+ async listDataComponents() {
156
+ const tenantId = this.checkTenantId();
157
+ const projectId = this.getProjectId();
158
+ const all = [];
159
+ let page = 1;
160
+ const limit = 100;
161
+ let result;
162
+ do {
163
+ const response = await this.authenticatedFetch(`${this.apiUrl}/manage/tenants/${tenantId}/projects/${projectId}/data-components?page=${page}&limit=${limit}`, { method: "GET" });
164
+ if (!response.ok) {
165
+ const err = await response.text().catch(() => "");
166
+ throw new Error(`Failed to list data components: ${response.statusText}${err ? `\n${err}` : ""}`);
167
+ }
168
+ result = await response.json();
169
+ all.push(...result.data || []);
170
+ page++;
171
+ } while (result.data?.length === limit && all.length < (result.pagination?.total ?? 0));
172
+ return all;
173
+ }
174
+ async getArtifactComponent(componentId) {
175
+ const tenantId = this.checkTenantId();
176
+ const projectId = this.getProjectId();
177
+ const response = await this.authenticatedFetch(`${this.apiUrl}/manage/tenants/${tenantId}/projects/${projectId}/artifact-components/${componentId}`, { method: "GET" });
178
+ if (response.status === 404) return null;
179
+ if (!response.ok) {
180
+ const err = await response.text().catch(() => "");
181
+ throw new Error(`Failed to fetch artifact component: ${response.statusText}${err ? `\n${err}` : ""}`);
182
+ }
183
+ return (await response.json()).data ?? null;
184
+ }
185
+ async listArtifactComponents() {
186
+ const tenantId = this.checkTenantId();
187
+ const projectId = this.getProjectId();
188
+ const all = [];
189
+ let page = 1;
190
+ const limit = 100;
191
+ let result;
192
+ do {
193
+ const response = await this.authenticatedFetch(`${this.apiUrl}/manage/tenants/${tenantId}/projects/${projectId}/artifact-components?page=${page}&limit=${limit}`, { method: "GET" });
194
+ if (!response.ok) {
195
+ const err = await response.text().catch(() => "");
196
+ throw new Error(`Failed to list artifact components: ${response.statusText}${err ? `\n${err}` : ""}`);
197
+ }
198
+ result = await response.json();
199
+ all.push(...result.data || []);
200
+ page++;
201
+ } while (result.data?.length === limit && all.length < (result.pagination?.total ?? 0));
202
+ return all;
203
+ }
144
204
  };
145
205
  var ExecutionApiClient = class ExecutionApiClient extends BaseApiClient {
146
206
  constructor(apiUrl, tenantId, projectId, apiKey, isCI = false) {
@@ -0,0 +1,179 @@
1
+ import { ManagementApiClient } from "../api.js";
2
+ import { findConfigFile, findProjectConfig } from "../utils/config.js";
3
+ import { initializeCommand } from "../utils/cli-pipeline.js";
4
+ import path from "node:path";
5
+ import * as p from "@clack/prompts";
6
+ import chalk from "chalk";
7
+ import { findUp } from "find-up";
8
+ import fs from "fs-extra";
9
+ import { Project } from "ts-morph";
10
+
11
+ //#region src/commands/add-ui.ts
12
+ const UI_DIR_RELATIVE = "apps/agents-ui/src/ui";
13
+ function toPascalCase(name) {
14
+ if (!name?.trim()) return "Component";
15
+ return name.trim().replace(/[-_]+/g, " ").split(/\s+/).map((word) => word.charAt(0).toUpperCase() + word.slice(1).toLowerCase()).join("");
16
+ }
17
+ /**
18
+ * Ensures the component declaration is exported using AST. Finds the first
19
+ * function or const component (PascalCase name) and adds export if missing.
20
+ */
21
+ function ensureExported(code) {
22
+ try {
23
+ const sourceFile = new Project({
24
+ useInMemoryFileSystem: true,
25
+ compilerOptions: { jsx: 1 }
26
+ }).createSourceFile("temp.tsx", code);
27
+ const candidates = [];
28
+ for (const fn of sourceFile.getFunctions()) if (fn.getName()) candidates.push({
29
+ start: fn.getStart(),
30
+ type: "function",
31
+ node: fn
32
+ });
33
+ for (const stmt of sourceFile.getVariableStatements()) {
34
+ const name = stmt.getDeclarationList().getDeclarations()[0]?.getName?.();
35
+ if (typeof name === "string" && name.length > 0 && name[0] === name[0].toUpperCase()) candidates.push({
36
+ start: stmt.getStart(),
37
+ type: "variable",
38
+ node: stmt
39
+ });
40
+ }
41
+ candidates.sort((a, b) => a.start - b.start);
42
+ const first = candidates[0];
43
+ if (!first) return code;
44
+ if (first.type === "function") {
45
+ if (!first.node.isExported()) first.node.setIsExported(true);
46
+ } else if (!first.node.hasExportKeyword()) first.node.toggleModifier("export", true);
47
+ return sourceFile.getFullText();
48
+ } catch {
49
+ return code;
50
+ }
51
+ }
52
+ async function findUiDirectory() {
53
+ const cwd = process.cwd();
54
+ const uiDir = path.join(cwd, UI_DIR_RELATIVE);
55
+ if (await fs.pathExists(uiDir)) return uiDir;
56
+ const found = await findUp(UI_DIR_RELATIVE, { type: "directory" });
57
+ if (found) return found;
58
+ const agentsUi = await findUp("apps/agents-ui", { type: "directory" });
59
+ if (agentsUi) return path.join(agentsUi, "src", "ui");
60
+ return path.join(cwd, UI_DIR_RELATIVE);
61
+ }
62
+ async function fetchAllComponentsWithRender(client) {
63
+ const [dataComponents, artifactComponents] = await Promise.all([client.listDataComponents(), client.listArtifactComponents()]);
64
+ return {
65
+ data: dataComponents,
66
+ artifact: artifactComponents
67
+ };
68
+ }
69
+ function formatComponentList(data, artifact) {
70
+ const withRender = (c) => c.render?.component?.trim();
71
+ const lines = [];
72
+ for (const c of data.filter(withRender)) lines.push(` ${chalk.cyan(c.id)} ${chalk.gray("(data)")} ${c.name}`);
73
+ for (const c of artifact.filter(withRender)) lines.push(` ${chalk.cyan(c.id)} ${chalk.gray("(artifact)")} ${c.name}`);
74
+ return lines.length ? lines.join("\n") : " (none with render code)";
75
+ }
76
+ async function addUiCommand(options) {
77
+ const componentId = typeof options.ui === "string" ? options.ui : void 0;
78
+ const configPath = options.config ? path.resolve(process.cwd(), options.config) : findConfigFile(process.cwd());
79
+ if (!configPath) {
80
+ console.error(chalk.red("No Inkeep config found. Run from a project directory with inkeep.config.ts or pass --config <path>."));
81
+ process.exit(1);
82
+ }
83
+ const { config, isCI } = await initializeCommand({
84
+ configPath,
85
+ profileName: options.profile,
86
+ showSpinner: true,
87
+ spinnerText: "Loading configuration...",
88
+ logConfig: !options.quiet,
89
+ quiet: options.quiet
90
+ });
91
+ const projectId = (await findProjectConfig(path.dirname(configPath)))?.projectId ?? null;
92
+ if (!projectId) {
93
+ console.error(chalk.red("Project ID not found in config. Set projectId in your inkeep.config.ts."));
94
+ process.exit(1);
95
+ }
96
+ if (!config.agentsApiKey) {
97
+ console.error(chalk.red("Not authenticated. Run \"inkeep login\" or set agentsApi.apiKey in your config."));
98
+ process.exit(1);
99
+ }
100
+ let client;
101
+ try {
102
+ client = await ManagementApiClient.create(config.agentsApiUrl, configPath, config.tenantId, projectId, isCI ?? false, config.agentsApiKey);
103
+ } catch (err) {
104
+ const message = err instanceof Error ? err.message : String(err);
105
+ console.error(chalk.red(`Failed to create API client: ${message}`));
106
+ process.exit(1);
107
+ }
108
+ const toWrite = [];
109
+ const s = p.spinner();
110
+ if (options.list) {
111
+ s.start("Fetching components...");
112
+ const { data: dataComponents, artifact: artifactComponents } = await fetchAllComponentsWithRender(client);
113
+ s.stop();
114
+ console.log(chalk.cyan("\nAvailable UI components (use id with inkeep add --ui <id>):\n"));
115
+ console.log(formatComponentList(dataComponents, artifactComponents));
116
+ console.log("");
117
+ process.exit(0);
118
+ }
119
+ s.start("Resolving UI directory...");
120
+ const uiDir = await findUiDirectory();
121
+ await fs.ensureDir(uiDir);
122
+ s.stop();
123
+ if (componentId) {
124
+ let comp = await client.getDataComponent(componentId);
125
+ let kind = "data";
126
+ if (!comp) {
127
+ comp = await client.getArtifactComponent(componentId);
128
+ kind = "artifact";
129
+ }
130
+ if (!comp) {
131
+ s.start("Fetching available components...");
132
+ const { data: dataComponents, artifact: artifactComponents } = await fetchAllComponentsWithRender(client);
133
+ s.stop();
134
+ console.error(chalk.red(`Component "${componentId}" not found (tried data and artifact components).`));
135
+ console.log(chalk.cyan("\nAvailable UI components (use id with inkeep add --ui <id>):\n"));
136
+ console.log(formatComponentList(dataComponents, artifactComponents));
137
+ console.log("");
138
+ process.exit(1);
139
+ }
140
+ if (!comp.render?.component?.trim()) {
141
+ console.error(chalk.red(`Component "${comp.name}" (${kind}) has no render code. Generate a render in the dashboard first.`));
142
+ process.exit(1);
143
+ }
144
+ const pascalName = toPascalCase(comp.name);
145
+ toWrite.push({
146
+ pascalName,
147
+ code: ensureExported(comp.render.component)
148
+ });
149
+ } else {
150
+ s.start("Fetching data and artifact components...");
151
+ const [dataComponents, artifactComponents] = await Promise.all([client.listDataComponents(), client.listArtifactComponents()]);
152
+ s.stop();
153
+ const withRender = (c) => c.render?.component?.trim() ? {
154
+ pascalName: toPascalCase(c.name),
155
+ code: ensureExported(c.render.component)
156
+ } : null;
157
+ for (const c of dataComponents) {
158
+ const item = withRender(c);
159
+ if (item) toWrite.push(item);
160
+ }
161
+ for (const c of artifactComponents) {
162
+ const item = withRender(c);
163
+ if (item) toWrite.push(item);
164
+ }
165
+ if (toWrite.length === 0) {
166
+ console.log(chalk.yellow("No components with render code found. Generate renders in the dashboard first."));
167
+ process.exit(0);
168
+ }
169
+ }
170
+ s.start(`Writing ${toWrite.length} component(s) to ${uiDir}...`);
171
+ for (const { pascalName, code } of toWrite) {
172
+ const filePath = path.join(uiDir, `${pascalName}.tsx`);
173
+ await fs.writeFile(filePath, code, "utf-8");
174
+ }
175
+ s.stop(chalk.green(`Added ${toWrite.length} component(s) to ${path.relative(process.cwd(), uiDir)}. Import with: import { <Name> } from './ui/<Name>';`));
176
+ }
177
+
178
+ //#endregion
179
+ export { addUiCommand, ensureExported };
@@ -1,4 +1,5 @@
1
1
  import { cloneTemplate, cloneTemplateLocal, getAvailableTemplates } from "../utils/templates.js";
2
+ import { addUiCommand } from "./add-ui.js";
2
3
  import { ANTHROPIC_MODELS, GOOGLE_MODELS, OPENAI_MODELS } from "@inkeep/agents-core";
3
4
  import path from "node:path";
4
5
  import * as p from "@clack/prompts";
@@ -23,6 +24,16 @@ const defaultAnthropicModelConfigurations = {
23
24
  summarizer: { model: ANTHROPIC_MODELS.CLAUDE_SONNET_4_5 }
24
25
  };
25
26
  async function addCommand(options) {
27
+ if (options.ui !== void 0) {
28
+ await addUiCommand({
29
+ ui: options.ui,
30
+ list: options.list,
31
+ config: options.config,
32
+ profile: options.profile,
33
+ quiet: options.quiet
34
+ });
35
+ return;
36
+ }
26
37
  const projectTemplates = await getAvailableTemplates("template-projects", options.localPrefix);
27
38
  const mcpTemplates = await getAvailableTemplates("template-mcps", options.localPrefix);
28
39
  if (!options.project && !options.mcp) {
@@ -1,5 +1,5 @@
1
- import { randomBytes } from "node:crypto";
2
1
  import { Node, Project } from "ts-morph";
2
+ import { randomBytes } from "node:crypto";
3
3
 
4
4
  //#region src/commands/pull-v3/targeted-typescript-placeholders.ts
5
5
  /**
package/dist/index.js CHANGED
@@ -25,7 +25,7 @@ const packageJsonPath = join(dirname(fileURLToPath(import.meta.url)), "..", "pac
25
25
  const packageJson = JSON.parse(readFileSync(packageJsonPath, "utf-8"));
26
26
  const program = new Command();
27
27
  program.name("inkeep").description("CLI tool for Inkeep Agent Framework").version(packageJson.version);
28
- program.command("add [template]").description("Add a new template to the project").option("--project <template>", "Project template to add").option("--mcp <template>", "MCP template to add").option("--target-path <path>", "Target path to add the template to").option("--local-prefix <path_prefix>", "Use local templates from the given path prefix").option("--config <path>", "Path to configuration file").action(async (template, options) => {
28
+ program.command("add [template]").description("Add a new template to the project").option("--project <template>", "Project template to add").option("--mcp <template>", "MCP template to add").option("--ui [component-id]", "Add UI component(s) to apps/agents-ui/src/ui (omit id to add all)").option("--list", "List available UI components (use with --ui)").option("--target-path <path>", "Target path to add the template to").option("--local-prefix <path_prefix>", "Use local templates from the given path prefix").option("--config <path>", "Path to configuration file").option("--profile <name>", "Profile to use for authentication").option("--quiet", "Suppress profile/config logging").action(async (template, options) => {
29
29
  await addCommand({
30
30
  template,
31
31
  ...options
@@ -1,8 +1,8 @@
1
1
  import { getCredentialExpiryInfo, loadCredentials } from "./credentials.js";
2
- import { ProfileManager } from "./profiles/profile-manager.js";
3
- import "./profiles/index.js";
4
2
  import { detectCIEnvironment, loadCIEnvironmentConfig, logCIConfig } from "./ci-environment.js";
5
3
  import { validateConfiguration } from "./config.js";
4
+ import { ProfileManager } from "./profiles/profile-manager.js";
5
+ import "./profiles/index.js";
6
6
  import * as p from "@clack/prompts";
7
7
  import chalk from "chalk";
8
8
 
@@ -23,19 +23,28 @@ function isNestedConfig(config) {
23
23
  return config && config.agentsApi !== void 0;
24
24
  }
25
25
  /**
26
+ * Ensure URL has a scheme so fetch() works. Bare host:port gets http://.
27
+ */
28
+ function ensureUrlScheme(url) {
29
+ if (!url?.trim()) return url;
30
+ const u = url.trim();
31
+ if (/^https?:\/\//i.test(u)) return u;
32
+ return `http://${u}`;
33
+ }
34
+ /**
26
35
  * Normalize config from either flat or nested format to internal format
27
36
  */
28
37
  function normalizeConfig(config) {
29
38
  if (isNestedConfig(config)) return {
30
39
  tenantId: config.tenantId,
31
- agentsApiUrl: config.agentsApi?.url,
40
+ agentsApiUrl: ensureUrlScheme(config.agentsApi?.url),
32
41
  agentsApiKey: config.agentsApi?.apiKey,
33
42
  manageUiUrl: config.manageUiUrl,
34
43
  outputDirectory: config.outputDirectory
35
44
  };
36
45
  return {
37
46
  tenantId: config.tenantId,
38
- agentsApiUrl: config.agentsApiUrl,
47
+ agentsApiUrl: ensureUrlScheme(config.agentsApiUrl),
39
48
  manageUiUrl: config.manageUiUrl,
40
49
  outputDirectory: config.outputDirectory
41
50
  };
@@ -254,6 +263,14 @@ async function validateConfiguration(configPath, tag) {
254
263
  config.agentsApiKey = cliCredentials.accessToken;
255
264
  logger.info({}, "Using CLI session token as API key");
256
265
  }
266
+ if (!config.agentsApiKey && !cliCredentials) {
267
+ const cloudCreds = await loadCredentials("inkeep-cloud");
268
+ if (cloudCreds?.accessToken) {
269
+ config.agentsApiKey = cloudCreds.accessToken;
270
+ if (!config.tenantId) config.tenantId = cloudCreds.organizationId;
271
+ logger.info({}, "Using CLI login credentials (inkeep-cloud)");
272
+ }
273
+ }
257
274
  if (!config.tenantId && cliCredentials) {
258
275
  config.tenantId = cliCredentials.organizationId;
259
276
  logger.info({}, "Using CLI organization ID as tenant ID");
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@inkeep/agents-cli",
3
- "version": "0.0.0-dev-20260212002106",
3
+ "version": "0.0.0-dev-20260212005842",
4
4
  "description": "Inkeep CLI tool",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -40,8 +40,8 @@
40
40
  "tsx": "^4.20.5",
41
41
  "yaml": "^2.7.0",
42
42
  "zod": "^4.3.6",
43
- "@inkeep/agents-core": "^0.0.0-dev-20260212002106",
44
- "@inkeep/agents-sdk": "^0.0.0-dev-20260212002106"
43
+ "@inkeep/agents-core": "^0.0.0-dev-20260212005842",
44
+ "@inkeep/agents-sdk": "^0.0.0-dev-20260212005842"
45
45
  },
46
46
  "devDependencies": {
47
47
  "@types/degit": "^2.8.6",
@@ -52,7 +52,7 @@
52
52
  "vitest": "^3.2.4"
53
53
  },
54
54
  "peerDependencies": {
55
- "@inkeep/agents-manage-ui": "0.0.0-dev-20260212002106"
55
+ "@inkeep/agents-manage-ui": "0.0.0-dev-20260212005842"
56
56
  },
57
57
  "publishConfig": {
58
58
  "access": "public",