@inkeep/agents-cli 0.47.5 ā 0.48.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/README.md +21 -596
- package/dist/api.js +60 -0
- package/dist/commands/add-ui.js +179 -0
- package/dist/commands/add.js +11 -0
- package/dist/commands/pull-v3/components/project-generator.js +16 -4
- package/dist/commands/pull-v3/components/skill-generator.js +23 -0
- package/dist/commands/pull-v3/components/sub-agent-generator.js +10 -0
- package/dist/commands/pull-v3/index.js +6 -1
- package/dist/commands/pull-v3/new-component-generator.js +2 -1
- package/dist/commands/pull-v3/targeted-typescript-placeholders.js +1 -1
- package/dist/commands/pull-v3/utils/component-registry.js +1 -0
- package/dist/index.js +2 -1
- package/dist/utils/cli-pipeline.js +2 -2
- package/dist/utils/config.js +19 -2
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -1,624 +1,49 @@
|
|
|
1
|
-
#
|
|
1
|
+
# @inkeep/agents-cli
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
CLI for working with the Inkeep Agent Framework.
|
|
4
4
|
|
|
5
|
-
##
|
|
6
|
-
|
|
7
|
-
### Prerequisites
|
|
8
|
-
|
|
9
|
-
- Node.js >= 20.x
|
|
10
|
-
- pnpm package manager
|
|
11
|
-
- Inkeep Agent Framework backend running (default: http://localhost:3002)
|
|
12
|
-
- `@inkeep/agents-manage-ui` package installed (for visual agents orchestration)
|
|
13
|
-
|
|
14
|
-
### Quick Start
|
|
15
|
-
|
|
16
|
-
> **š For detailed setup instructions, see [SETUP.md](./SETUP.md)**
|
|
17
|
-
|
|
18
|
-
1. **Install and build**
|
|
19
|
-
|
|
20
|
-
```bash
|
|
21
|
-
# Navigate to the CLI directory
|
|
22
|
-
cd /path/to/agent-framework/agents-cli
|
|
23
|
-
|
|
24
|
-
# Install dependencies
|
|
25
|
-
pnpm install
|
|
26
|
-
|
|
27
|
-
# Build the CLI
|
|
28
|
-
pnpm build
|
|
29
|
-
```
|
|
30
|
-
|
|
31
|
-
2. **Install globally** (recommended)
|
|
32
|
-
|
|
33
|
-
**Option A: Using npm link (for development)**
|
|
34
|
-
|
|
35
|
-
```bash
|
|
36
|
-
# Create global symlink from the agents-cli directory
|
|
37
|
-
npm link
|
|
38
|
-
|
|
39
|
-
# Verify installation
|
|
40
|
-
which inkeep # Should show path to inkeep command
|
|
41
|
-
```
|
|
42
|
-
|
|
43
|
-
**Option B: Using pnpm/npm global install (after publishing)**
|
|
44
|
-
|
|
45
|
-
```bash
|
|
46
|
-
# Install the scoped package globally
|
|
47
|
-
pnpm add -g @inkeep/agents-cli
|
|
48
|
-
# or
|
|
49
|
-
npm install -g @inkeep/agents-cli
|
|
50
|
-
|
|
51
|
-
# Verify installation
|
|
52
|
-
inkeep --version
|
|
53
|
-
```
|
|
54
|
-
|
|
55
|
-
**Note:**
|
|
56
|
-
|
|
57
|
-
- For local development, use `npm link` (more reliable than `pnpm link --global`)
|
|
58
|
-
- The command is still `inkeep` even though the package name is `@inkeep/agents-cli`
|
|
59
|
-
- If linking fails, try unlinking first: `npm unlink -g @inkeep/agents-cli`
|
|
60
|
-
|
|
61
|
-
3. **Install the dashboard package (for visual agents orchestration)**
|
|
5
|
+
## Install
|
|
62
6
|
|
|
63
7
|
```bash
|
|
64
|
-
|
|
65
|
-
npm install @inkeep/agents-manage-ui
|
|
8
|
+
npm install -g @inkeep/agents-cli
|
|
66
9
|
# or
|
|
67
|
-
pnpm add @inkeep/agents-
|
|
68
|
-
```
|
|
69
|
-
|
|
70
|
-
4. **Configure your project**
|
|
71
|
-
|
|
72
|
-
```bash
|
|
73
|
-
# Create an inkeep.config.ts file with your tenant ID
|
|
74
|
-
inkeep init
|
|
75
|
-
|
|
76
|
-
# Or manually create inkeep.config.ts:
|
|
77
|
-
# export default defineConfig({
|
|
78
|
-
# tenantId: "your-tenant-id",
|
|
79
|
-
# projectId: "your-project-id",
|
|
80
|
-
# agentsApiUrl: "http://localhost:3002",
|
|
81
|
-
# });
|
|
82
|
-
```
|
|
83
|
-
|
|
84
|
-
## Configuration
|
|
85
|
-
|
|
86
|
-
### Configuration Sources (priority order)
|
|
87
|
-
|
|
88
|
-
1. **Command-line flags** - Highest priority (e.g., `--tenant-id`, `--agents-api-url`, `--config`)
|
|
89
|
-
2. **Config file** - `inkeep.config.ts` (or file specified with `--config`)
|
|
90
|
-
3. **Environment variables** - `INKEEP_AGENTS_API_URL`
|
|
91
|
-
4. **Defaults** - Lowest priority (defaults to `http://localhost:3002`)
|
|
92
|
-
|
|
93
|
-
### Config File Options
|
|
94
|
-
|
|
95
|
-
Most commands support the `--config` option to specify a custom configuration file:
|
|
96
|
-
|
|
97
|
-
```bash
|
|
98
|
-
# Use custom config file
|
|
99
|
-
inkeep list-graphs --project my-project --config ./staging-config.ts
|
|
100
|
-
|
|
101
|
-
# Backward compatibility (deprecated)
|
|
102
|
-
inkeep list-graphs --project my-project --config-file-path ./staging-config.ts
|
|
103
|
-
```
|
|
104
|
-
|
|
105
|
-
### Environment Variables
|
|
106
|
-
|
|
107
|
-
Create a `.env` file in your project directory:
|
|
108
|
-
|
|
109
|
-
```bash
|
|
110
|
-
INKEEP_AGENTS_API_URL=http://localhost:3002
|
|
10
|
+
pnpm add -g @inkeep/agents-cli
|
|
111
11
|
```
|
|
112
12
|
|
|
113
|
-
|
|
13
|
+
The executable command is `inkeep`.
|
|
114
14
|
|
|
115
|
-
|
|
116
|
-
export INKEEP_AGENTS_API_URL=http://localhost:3002
|
|
117
|
-
```
|
|
118
|
-
|
|
119
|
-
## Commands
|
|
15
|
+
## Docs
|
|
120
16
|
|
|
121
|
-
|
|
17
|
+
- CLI overview: <https://docs.inkeep.com/guides/cli/overview>
|
|
18
|
+
- CLI reference: <https://docs.inkeep.com/typescript-sdk/cli-reference>
|
|
19
|
+
- Push guide: <https://docs.inkeep.com/guides/cli/push-to-cloud>
|
|
20
|
+
- Pull guide: <https://docs.inkeep.com/guides/cli/pull-from-cloud>
|
|
21
|
+
- Profile setup: <https://docs.inkeep.com/guides/cli/setup-profile>
|
|
122
22
|
|
|
123
|
-
|
|
23
|
+
## Quick usage
|
|
124
24
|
|
|
125
25
|
```bash
|
|
126
|
-
# Add a template
|
|
127
|
-
inkeep add my-template
|
|
128
|
-
|
|
129
|
-
# Add template to specific path
|
|
130
|
-
inkeep add my-template --target-path ./src/templates
|
|
131
|
-
|
|
132
|
-
# Using config file
|
|
133
|
-
inkeep add my-template --config ./my-config.ts
|
|
134
|
-
```
|
|
135
|
-
|
|
136
|
-
### `inkeep init [path]`
|
|
137
|
-
|
|
138
|
-
Initialize a new Inkeep configuration file.
|
|
139
|
-
|
|
140
|
-
```bash
|
|
141
|
-
# Interactive initialization
|
|
142
26
|
inkeep init
|
|
143
|
-
|
|
144
|
-
# Initialize in specific directory
|
|
145
|
-
inkeep init ./my-project
|
|
146
|
-
|
|
147
|
-
# Skip interactive prompts
|
|
148
|
-
inkeep init --no-interactive
|
|
149
|
-
|
|
150
|
-
# Use existing config as template
|
|
151
|
-
inkeep init --config ./template-config.ts
|
|
152
|
-
```
|
|
153
|
-
|
|
154
|
-
### `inkeep config`
|
|
155
|
-
|
|
156
|
-
Manage Inkeep configuration values.
|
|
157
|
-
|
|
158
|
-
```bash
|
|
159
|
-
# Get configuration value
|
|
160
|
-
inkeep config get tenantId
|
|
161
|
-
|
|
162
|
-
# Set configuration value
|
|
163
|
-
inkeep config set tenantId my-tenant-id
|
|
164
|
-
|
|
165
|
-
# List all configuration values
|
|
166
|
-
inkeep config list
|
|
167
|
-
|
|
168
|
-
# Using specific config file
|
|
169
|
-
inkeep config get tenantId --config ./my-config.ts
|
|
170
|
-
```
|
|
171
|
-
|
|
172
|
-
### `inkeep pull`
|
|
173
|
-
|
|
174
|
-
Pull entire project configuration from backend and update local files.
|
|
175
|
-
|
|
176
|
-
```bash
|
|
177
|
-
# Pull current project
|
|
178
|
-
inkeep pull
|
|
179
|
-
|
|
180
|
-
# Pull specific project
|
|
181
|
-
inkeep pull --project my-project-id
|
|
182
|
-
|
|
183
|
-
# Generate environment file
|
|
184
|
-
inkeep pull --env production
|
|
185
|
-
|
|
186
|
-
# Generate JSON file instead of updating files
|
|
187
|
-
inkeep pull --json
|
|
188
|
-
|
|
189
|
-
# Enable debug logging
|
|
190
|
-
inkeep pull --debug
|
|
191
|
-
|
|
192
|
-
# Using config file
|
|
193
|
-
inkeep pull --project my-project-id --config ./my-config.ts
|
|
194
|
-
```
|
|
195
|
-
|
|
196
|
-
### `inkeep dev`
|
|
197
|
-
|
|
198
|
-
Start the Inkeep dashboard server, build for production, or export the Next.js project.
|
|
199
|
-
|
|
200
|
-
```bash
|
|
201
|
-
# Start development server
|
|
202
|
-
inkeep dev
|
|
203
|
-
|
|
204
|
-
# Start on custom port and host
|
|
205
|
-
inkeep dev --port 3001 --host 0.0.0.0
|
|
206
|
-
|
|
207
|
-
# Build for production (packages standalone build)
|
|
208
|
-
inkeep dev --build --output-dir ./build
|
|
209
|
-
|
|
210
|
-
# Export Next.js project source files
|
|
211
|
-
inkeep dev --export --output-dir ./my-dashboard
|
|
212
|
-
|
|
213
|
-
# Get dashboard path for deployment
|
|
214
|
-
DASHBOARD_PATH=$(inkeep dev --path)
|
|
215
|
-
echo "Dashboard built at: $DASHBOARD_PATH"
|
|
216
|
-
|
|
217
|
-
# Use with Vercel
|
|
218
|
-
vercel --cwd $(inkeep dev --path) -Q .vercel build
|
|
219
|
-
|
|
220
|
-
# Use with Docker
|
|
221
|
-
docker build -t inkeep-dashboard $(inkeep dev --path)
|
|
222
|
-
|
|
223
|
-
# Use with other deployment tools
|
|
224
|
-
rsync -av $(inkeep dev --path)/ user@server:/var/www/dashboard/
|
|
225
|
-
```
|
|
226
|
-
|
|
227
|
-
### `inkeep tenant [tenant-id]` ā ļø NOT IMPLEMENTED
|
|
228
|
-
|
|
229
|
-
> **ā ļø WARNING: This command is not yet implemented in the current CLI.**
|
|
230
|
-
> Use `inkeep.config.ts` to set your tenant ID instead.
|
|
231
|
-
|
|
232
|
-
Manage tenant configuration.
|
|
233
|
-
|
|
234
|
-
```bash
|
|
235
|
-
# Set tenant ID
|
|
236
|
-
inkeep tenant my-tenant
|
|
237
|
-
|
|
238
|
-
# View current tenant ID
|
|
239
|
-
inkeep tenant
|
|
240
|
-
```
|
|
241
|
-
|
|
242
|
-
### `inkeep list-graphs`
|
|
243
|
-
|
|
244
|
-
List all available graphs for a specific project.
|
|
245
|
-
|
|
246
|
-
```bash
|
|
247
|
-
# List graphs for a project (required)
|
|
248
|
-
inkeep list-graphs --project my-project-id
|
|
249
|
-
|
|
250
|
-
# With custom API URL
|
|
251
|
-
inkeep list-graphs --project my-project-id --agent-api-url http://api.example.com:3002
|
|
252
|
-
|
|
253
|
-
# With custom tenant ID
|
|
254
|
-
inkeep list-graphs --project my-project-id --tenant-id my-tenant-id
|
|
255
|
-
|
|
256
|
-
# Using config file
|
|
257
|
-
inkeep list-agents --project my-project-id --config ./my-config.ts
|
|
258
|
-
```
|
|
259
|
-
|
|
260
|
-
Output:
|
|
261
|
-
|
|
262
|
-
```
|
|
263
|
-
āāāāāāāāāāāāāāāāāāāāāāāāāāā¬āāāāāāāāāāāāāāāāāāāāā¬āāāāāāāāāāāāāāāā¬āāāāāāāāāāāā
|
|
264
|
-
ā Agent ID ā Name ā Default Agent ā Created ā
|
|
265
|
-
āāāāāāāāāāāāāāāāāāāāāāāāāāā¼āāāāāāāāāāāāāāāāāāāāā¼āāāāāāāāāāāāāāāā¼āāāāāāāāāāāā¤
|
|
266
|
-
ā customer-support-graph ā Customer Support ā router ā 1/15/2025 ā
|
|
267
|
-
ā qa-assistant ā QA Assistant ā qa-agent ā 1/14/2025 ā
|
|
268
|
-
āāāāāāāāāāāāāāāāāāāāāāāāāāā“āāāāāāāāāāāāāāāāāāāāā“āāāāāāāāāāāāāāāā“āāāāāāāāāāāā
|
|
269
|
-
```
|
|
270
|
-
|
|
271
|
-
### `inkeep push`
|
|
272
|
-
|
|
273
|
-
Push your project configuration to the backend.
|
|
274
|
-
|
|
275
|
-
```bash
|
|
276
|
-
# Push the current project (from the directory with inkeep.config.ts)
|
|
277
27
|
inkeep push
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
inkeep push --project my-project-id
|
|
281
|
-
|
|
282
|
-
# With custom configuration
|
|
283
|
-
inkeep push --project my-project-id --config ./my-config.ts
|
|
284
|
-
|
|
285
|
-
# With custom API URLs
|
|
286
|
-
inkeep push --project my-project-id --agents-api-url http://api.example.com
|
|
287
|
-
|
|
288
|
-
# With custom tenant ID
|
|
289
|
-
inkeep push --project my-project-id --tenant-id my-tenant-id
|
|
290
|
-
```
|
|
291
|
-
|
|
292
|
-
**Features:**
|
|
293
|
-
|
|
294
|
-
- Automatically injects tenant ID and API URL from `inkeep.config.ts`
|
|
295
|
-
- Validates exactly one Agent is exported
|
|
296
|
-
- Warns about dangling resources (unreferenced agents/tools)
|
|
297
|
-
- Shows graph summary after successful push
|
|
298
|
-
- Handles graph initialization automatically
|
|
299
|
-
|
|
300
|
-
**Agent files:** Define your agents in your project (e.g., `agents/*.ts`). The CLI pushes the project containing those agents.
|
|
301
|
-
|
|
302
|
-
**Example graph configuration:**
|
|
303
|
-
|
|
304
|
-
```javascript
|
|
305
|
-
// customer-support.agent.ts
|
|
306
|
-
import { agent, subAgent, tool } from "@inkeep/agents-sdk";
|
|
307
|
-
|
|
308
|
-
const assistantSubAgent = subAgent({
|
|
309
|
-
id: "assistant",
|
|
310
|
-
name: "Assistant",
|
|
311
|
-
prompt: "Help users with their questions",
|
|
312
|
-
canUse: () => [searchTool],
|
|
313
|
-
// No tenantId needed - injected by CLI
|
|
314
|
-
});
|
|
315
|
-
|
|
316
|
-
// Must export exactly one agent
|
|
317
|
-
export const myAgent = agent({
|
|
318
|
-
id: "my-assistant",
|
|
319
|
-
name: "My Assistant",
|
|
320
|
-
defaultSubAgent: assistantSubAgent,
|
|
321
|
-
subAgents: () => [assistantSubAgent],
|
|
322
|
-
// No tenantId or apiUrl needed - CLI injects from config
|
|
323
|
-
});
|
|
324
|
-
// No agent.init() call - CLI handles initialization
|
|
325
|
-
```
|
|
326
|
-
|
|
327
|
-
### `inkeep mcp start <graph-file>` ā ļø NOT IMPLEMENTED
|
|
328
|
-
|
|
329
|
-
> **ā ļø WARNING: This command is not yet implemented in the current CLI.**
|
|
330
|
-
> MCP functionality is planned but not available in the current version.
|
|
331
|
-
|
|
332
|
-
Start MCP (Model Context Protocol) servers defined in a graph file.
|
|
333
|
-
|
|
334
|
-
```bash
|
|
335
|
-
# Start MCP servers from a TypeScript agent file
|
|
336
|
-
inkeep mcp start examples/agent-configurations/weather-agent.ts
|
|
337
|
-
|
|
338
|
-
# Start from compiled JavaScript
|
|
339
|
-
inkeep mcp start dist/examples/agent-configurations/weather-agent.js
|
|
340
|
-
|
|
341
|
-
# Run in detached mode
|
|
342
|
-
inkeep mcp start my-agent.ts --detached
|
|
343
|
-
|
|
344
|
-
# Show verbose output
|
|
345
|
-
inkeep mcp start my-agent.ts --verbose
|
|
346
|
-
```
|
|
347
|
-
|
|
348
|
-
**Features:**
|
|
349
|
-
|
|
350
|
-
- Supports both TypeScript (`.ts`) and JavaScript (`.js`) files
|
|
351
|
-
- Automatically allocates ports for local servers (3100-3200)
|
|
352
|
-
- Shows server names, ports, and URLs
|
|
353
|
-
- Distinguishes between local (š ) and remote (āļø) servers
|
|
354
|
-
|
|
355
|
-
### `inkeep mcp stop` ā ļø NOT IMPLEMENTED
|
|
356
|
-
|
|
357
|
-
> **ā ļø WARNING: This command is not yet implemented in the current CLI.**
|
|
358
|
-
|
|
359
|
-
Stop running MCP servers.
|
|
360
|
-
|
|
361
|
-
```bash
|
|
362
|
-
# Stop all servers
|
|
363
|
-
inkeep mcp stop --all
|
|
364
|
-
|
|
365
|
-
# Stop servers for a specific graph
|
|
366
|
-
inkeep mcp stop --graph customer-support-graph
|
|
367
|
-
```
|
|
368
|
-
|
|
369
|
-
### `inkeep mcp status` ā ļø NOT IMPLEMENTED
|
|
370
|
-
|
|
371
|
-
> **ā ļø WARNING: This command is not yet implemented in the current CLI.**
|
|
372
|
-
|
|
373
|
-
Show status of all MCP servers.
|
|
374
|
-
|
|
375
|
-
```bash
|
|
376
|
-
inkeep mcp status
|
|
377
|
-
```
|
|
378
|
-
|
|
379
|
-
Output shows:
|
|
380
|
-
|
|
381
|
-
- Process ID
|
|
382
|
-
- Graph ID
|
|
383
|
-
- Tool name
|
|
384
|
-
- Port/URL
|
|
385
|
-
- Running status
|
|
386
|
-
- Uptime
|
|
387
|
-
|
|
388
|
-
### `inkeep mcp list` ā ļø NOT IMPLEMENTED
|
|
389
|
-
|
|
390
|
-
> **ā ļø WARNING: This command is not yet implemented in the current CLI.**
|
|
391
|
-
|
|
392
|
-
List all MCP servers with detailed information.
|
|
393
|
-
|
|
394
|
-
```bash
|
|
395
|
-
# Default tree view
|
|
396
|
-
inkeep mcp list
|
|
397
|
-
|
|
398
|
-
# Table format
|
|
399
|
-
inkeep mcp list --format table
|
|
400
|
-
|
|
401
|
-
# Verbose output (includes descriptions)
|
|
402
|
-
inkeep mcp list --verbose
|
|
28
|
+
inkeep pull
|
|
29
|
+
inkeep list-agent --project <project-id>
|
|
403
30
|
```
|
|
404
31
|
|
|
405
|
-
##
|
|
406
|
-
|
|
407
|
-
### Basic Setup
|
|
32
|
+
## Local development
|
|
408
33
|
|
|
409
34
|
```bash
|
|
410
|
-
# Install and link CLI
|
|
411
|
-
cd agents-cli
|
|
412
35
|
pnpm install
|
|
413
36
|
pnpm build
|
|
414
37
|
npm link
|
|
415
|
-
|
|
416
|
-
# Initialize configuration
|
|
417
|
-
inkeep init
|
|
418
|
-
# Edit inkeep.config.ts to set your tenantId and projectId
|
|
419
|
-
```
|
|
420
|
-
|
|
421
|
-
### Working with Graphs and MCP Servers ā ļø NOT AVAILABLE
|
|
422
|
-
|
|
423
|
-
> **ā ļø WARNING: MCP commands shown below are not yet implemented.**
|
|
424
|
-
> This section shows planned functionality that is not available in the current version.
|
|
425
|
-
|
|
426
|
-
1. **Create an agent with MCP tools** (`my-agent.ts`)
|
|
427
|
-
|
|
428
|
-
```typescript
|
|
429
|
-
import {
|
|
430
|
-
agent,
|
|
431
|
-
subAgent,
|
|
432
|
-
mcpServer,
|
|
433
|
-
} from "@inkeep/agents-sdk";
|
|
434
|
-
|
|
435
|
-
// Define MCP servers (tools)
|
|
436
|
-
const randomNumberServer = mcpServer({
|
|
437
|
-
name: "random_number",
|
|
438
|
-
description: "Generates a random number",
|
|
439
|
-
execute: async () => Math.random(),
|
|
440
|
-
});
|
|
441
|
-
|
|
442
|
-
const weatherServer = mcpServer({
|
|
443
|
-
name: "weather_api",
|
|
444
|
-
description: "Get weather information",
|
|
445
|
-
serverUrl: "https://api.weather.example.com/mcp",
|
|
446
|
-
});
|
|
447
|
-
|
|
448
|
-
// Define sub-agents
|
|
449
|
-
const assistantSubAgent = subAgent({
|
|
450
|
-
id: "assistant",
|
|
451
|
-
name: "Assistant",
|
|
452
|
-
prompt: "Help users with various tasks",
|
|
453
|
-
canUse: () => [randomNumberServer, weatherServer],
|
|
454
|
-
});
|
|
455
|
-
|
|
456
|
-
// Export the agent
|
|
457
|
-
export const myAgent = agent({
|
|
458
|
-
id: "my-assistant",
|
|
459
|
-
name: "My Assistant",
|
|
460
|
-
defaultSubAgent: assistantSubAgent,
|
|
461
|
-
subAgents: () => [assistantSubAgent],
|
|
462
|
-
});
|
|
463
|
-
|
|
464
|
-
// Export servers for MCP management
|
|
465
|
-
export const servers = [randomNumberServer, weatherServer];
|
|
466
|
-
```
|
|
467
|
-
|
|
468
|
-
2. **Monitor and manage servers**
|
|
469
|
-
|
|
470
|
-
```bash
|
|
471
|
-
# Check server status
|
|
472
|
-
inkeep mcp status
|
|
473
|
-
|
|
474
|
-
# List all servers with details
|
|
475
|
-
inkeep mcp list
|
|
476
|
-
|
|
477
|
-
# Stop servers when done
|
|
478
|
-
inkeep mcp stop --all
|
|
38
|
+
inkeep --version
|
|
479
39
|
```
|
|
480
40
|
|
|
481
|
-
##
|
|
41
|
+
## Contributing
|
|
482
42
|
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
```bash
|
|
486
|
-
# Using environment variables
|
|
487
|
-
INKEEP_AGENTS_MANAGE_API_URL=http://localhost:3002 inkeep list-graphs
|
|
488
|
-
|
|
489
|
-
# Using .env file
|
|
490
|
-
echo "INKEEP_AGENTS_API_URL=http://localhost:3002" > .env
|
|
491
|
-
```
|
|
492
|
-
|
|
493
|
-
### Staging
|
|
494
|
-
|
|
495
|
-
```bash
|
|
496
|
-
# Set in config file
|
|
497
|
-
# Edit your inkeep.config.ts:
|
|
498
|
-
# agentsApiUrl: 'https://staging-api.example.com'
|
|
499
|
-
```
|
|
500
|
-
|
|
501
|
-
### Production
|
|
502
|
-
|
|
503
|
-
```bash
|
|
504
|
-
# Using environment variables
|
|
505
|
-
export INKEEP_AGENTS_API_URL=https://inkeep-api.example.com
|
|
506
|
-
inkeep list-graphs
|
|
507
|
-
```
|
|
508
|
-
|
|
509
|
-
## Development
|
|
510
|
-
|
|
511
|
-
### Running from Source
|
|
512
|
-
|
|
513
|
-
```bash
|
|
514
|
-
# Without building (using tsx)
|
|
515
|
-
pnpm tsx src/index.ts <command>
|
|
516
|
-
|
|
517
|
-
# After building
|
|
518
|
-
node dist/index.js <command>
|
|
519
|
-
|
|
520
|
-
# Watch mode (auto-rebuild on changes)
|
|
521
|
-
pnpm dev
|
|
522
|
-
```
|
|
523
|
-
|
|
524
|
-
### Testing
|
|
525
|
-
|
|
526
|
-
```bash
|
|
527
|
-
# Run tests
|
|
528
|
-
pnpm test
|
|
529
|
-
|
|
530
|
-
# Watch mode
|
|
531
|
-
pnpm test:watch
|
|
532
|
-
|
|
533
|
-
# Coverage report
|
|
534
|
-
pnpm test:coverage
|
|
535
|
-
```
|
|
536
|
-
|
|
537
|
-
### Type Checking
|
|
43
|
+
Run from `agents-cli/`:
|
|
538
44
|
|
|
539
45
|
```bash
|
|
46
|
+
pnpm lint
|
|
540
47
|
pnpm typecheck
|
|
48
|
+
pnpm test --run
|
|
541
49
|
```
|
|
542
|
-
|
|
543
|
-
### Project Structure
|
|
544
|
-
|
|
545
|
-
```
|
|
546
|
-
agents-cli/
|
|
547
|
-
āāā src/
|
|
548
|
-
ā āāā index.ts # Main CLI entry point
|
|
549
|
-
ā āāā config.ts # Configuration management
|
|
550
|
-
ā āāā api.ts # API client for backend
|
|
551
|
-
ā āāā commands/ # Command implementations
|
|
552
|
-
ā ā āāā push.ts # Push graph configurations
|
|
553
|
-
ā ā āāā tenant.ts # Tenant management
|
|
554
|
-
ā ā āāā list-graphs.ts # List graphs
|
|
555
|
-
ā āāā types/ # TypeScript declarations
|
|
556
|
-
ā āāā __tests__/ # Test files
|
|
557
|
-
āāā dist/ # Compiled JavaScript
|
|
558
|
-
āāā package.json
|
|
559
|
-
āāā tsconfig.json
|
|
560
|
-
āāā README.md
|
|
561
|
-
```
|
|
562
|
-
|
|
563
|
-
## Troubleshooting
|
|
564
|
-
|
|
565
|
-
### Common Issues
|
|
566
|
-
|
|
567
|
-
**"Failed to fetch graphs" or connection errors**
|
|
568
|
-
|
|
569
|
-
```bash
|
|
570
|
-
# Check if backend is running
|
|
571
|
-
curl http://localhost:3002/health
|
|
572
|
-
|
|
573
|
-
# Verify API URLs
|
|
574
|
-
echo $INKEEP_AGENTS_API_URL
|
|
575
|
-
|
|
576
|
-
# Try with explicit URL and project
|
|
577
|
-
inkeep list-graphs --project my-project-id --agents-api-url http://localhost:3002
|
|
578
|
-
```
|
|
579
|
-
|
|
580
|
-
**Command not found: inkeep**
|
|
581
|
-
|
|
582
|
-
```bash
|
|
583
|
-
# Ensure CLI is linked globally
|
|
584
|
-
cd agents-cli
|
|
585
|
-
npm link
|
|
586
|
-
|
|
587
|
-
# Or if published, install globally
|
|
588
|
-
pnpm add -g @inkeep/agents-cli
|
|
589
|
-
# or
|
|
590
|
-
npm install -g @inkeep/agents-cli
|
|
591
|
-
|
|
592
|
-
# Or add to PATH manually (for development)
|
|
593
|
-
export PATH="$PATH:/path/to/agents-cli/dist"
|
|
594
|
-
```
|
|
595
|
-
|
|
596
|
-
## Dependencies
|
|
597
|
-
|
|
598
|
-
### Runtime Dependencies
|
|
599
|
-
|
|
600
|
-
- **commander**: Command-line framework
|
|
601
|
-
- **chalk**: Terminal styling
|
|
602
|
-
- **dotenv**: Environment variable loading
|
|
603
|
-
- **ora**: Loading spinners
|
|
604
|
-
- **cli-table3**: Table formatting
|
|
605
|
-
- **inquirer**: Interactive prompts
|
|
606
|
-
- **inquirer-autocomplete-prompt**: Searchable selections
|
|
607
|
-
|
|
608
|
-
### Development Dependencies
|
|
609
|
-
|
|
610
|
-
- **typescript**: TypeScript compiler
|
|
611
|
-
- **@types/node**: Node.js types
|
|
612
|
-
- **vitest**: Testing framework
|
|
613
|
-
- **@vitest/coverage-v8**: Coverage reporting
|
|
614
|
-
|
|
615
|
-
## Requirements
|
|
616
|
-
|
|
617
|
-
- Node.js >= 20.x
|
|
618
|
-
- pnpm package manager
|
|
619
|
-
- TypeScript 5.x
|
|
620
|
-
- Inkeep Agent Framework backend
|
|
621
|
-
|
|
622
|
-
## License
|
|
623
|
-
|
|
624
|
-
MIT
|
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 };
|
package/dist/commands/add.js
CHANGED
|
@@ -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) {
|
|
@@ -20,6 +20,7 @@ function generateProjectDefinition(projectId, projectData, style = DEFAULT_STYLE
|
|
|
20
20
|
lines.push(`${indentation}name: ${formatString(projectData.name, q)},`);
|
|
21
21
|
if (shouldInclude(projectData.description)) lines.push(`${indentation}description: ${formatString(projectData.description, q, true)},`);
|
|
22
22
|
if (shouldInclude(projectData.models)) lines.push(`${indentation}models: ${formatObject(projectData.models, style, 2)},`);
|
|
23
|
+
if (shouldInclude(projectData.skills)) lines.push(`${indentation}skills: () => loadSkills(path.join(${formatString(projectId, q)}, 'skills')),`);
|
|
23
24
|
if (shouldInclude(projectData.stopWhen)) {
|
|
24
25
|
lines.push(`${indentation}stopWhen: {`);
|
|
25
26
|
if (projectData.stopWhen.transferCountIs !== void 0) lines.push(`${indentation}${indentation}transferCountIs: ${projectData.stopWhen.transferCountIs}, // Max transfers for agents`);
|
|
@@ -64,7 +65,14 @@ function generateProjectDefinition(projectId, projectData, style = DEFAULT_STYLE
|
|
|
64
65
|
*/
|
|
65
66
|
function generateProjectImports(projectData, style = DEFAULT_STYLE, registry) {
|
|
66
67
|
const imports = [];
|
|
67
|
-
|
|
68
|
+
const sdkImports = ["project"];
|
|
69
|
+
if (shouldInclude(projectData.skills)) sdkImports.push("loadSkills");
|
|
70
|
+
imports.push(generateImport(sdkImports, "@inkeep/agents-sdk", style));
|
|
71
|
+
if (shouldInclude(projectData.skills)) {
|
|
72
|
+
const q = style.quotes === "single" ? "'" : "\"";
|
|
73
|
+
const semi = style.semicolons ? ";" : "";
|
|
74
|
+
imports.push(`import path from ${q}node:path${q}${semi}`);
|
|
75
|
+
}
|
|
68
76
|
if (registry) {
|
|
69
77
|
const currentFilePath = "index.ts";
|
|
70
78
|
const referencedComponents = [];
|
|
@@ -83,8 +91,8 @@ function generateProjectImports(projectData, style = DEFAULT_STYLE, registry) {
|
|
|
83
91
|
else if (typeof projectData.tools === "object") toolIds = Object.keys(projectData.tools);
|
|
84
92
|
for (const toolId of toolIds) {
|
|
85
93
|
let componentType = "tools";
|
|
86
|
-
if (registry
|
|
87
|
-
else if (registry
|
|
94
|
+
if (registry.get(toolId, "functionTools")) componentType = "functionTools";
|
|
95
|
+
else if (registry.get(toolId, "tools")) componentType = "tools";
|
|
88
96
|
referencedComponents.push({
|
|
89
97
|
id: toolId,
|
|
90
98
|
type: componentType
|
|
@@ -138,7 +146,11 @@ function generateProjectImports(projectData, style = DEFAULT_STYLE, registry) {
|
|
|
138
146
|
* Generate complete project file (imports + definition)
|
|
139
147
|
*/
|
|
140
148
|
function generateProjectFile(projectId, projectData, style = DEFAULT_STYLE, registry) {
|
|
141
|
-
|
|
149
|
+
const imports = generateProjectImports(projectData, style, registry);
|
|
150
|
+
const definition = generateProjectDefinition(projectId, projectData, style, registry);
|
|
151
|
+
const definitions = [];
|
|
152
|
+
definitions.push(definition);
|
|
153
|
+
return generateFileContent(imports, definitions);
|
|
142
154
|
}
|
|
143
155
|
|
|
144
156
|
//#endregion
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { join } from "node:path";
|
|
2
|
+
import { stringify } from "yaml";
|
|
3
|
+
import { mkdir, writeFile } from "node:fs/promises";
|
|
4
|
+
|
|
5
|
+
//#region src/commands/pull-v3/components/skill-generator.ts
|
|
6
|
+
function formatMetadata(metadata) {
|
|
7
|
+
return `metadata:\n${stringify(metadata).split("\n").filter((line) => line.trim() !== "").map((line) => ` ${line}`).join("\n")}`;
|
|
8
|
+
}
|
|
9
|
+
async function generateSkills(skills, skillsDir) {
|
|
10
|
+
await mkdir(skillsDir, { recursive: true });
|
|
11
|
+
for (const [skillId, skill] of Object.entries(skills)) {
|
|
12
|
+
const parts = ["---", `name: ${JSON.stringify(skill.name)}`];
|
|
13
|
+
parts.push(`description: ${JSON.stringify(skill.description ?? "")}`);
|
|
14
|
+
if (skill.metadata && Object.keys(skill.metadata).length > 0) parts.push(formatMetadata(skill.metadata));
|
|
15
|
+
parts.push("---", "", skill.content || "");
|
|
16
|
+
const skillDir = join(skillsDir, skillId);
|
|
17
|
+
await mkdir(skillDir, { recursive: true });
|
|
18
|
+
await writeFile(join(skillDir, "SKILL.md"), parts.join("\n"), "utf8");
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
//#endregion
|
|
23
|
+
export { generateSkills };
|
|
@@ -94,6 +94,16 @@ function generateSubAgentDefinition(agentId, agentData, style = DEFAULT_STYLE, r
|
|
|
94
94
|
removeTrailingComma(lines);
|
|
95
95
|
lines.push(`${indentation}},`);
|
|
96
96
|
}
|
|
97
|
+
if (Array.isArray(agentData.skills) && agentData.skills.length) {
|
|
98
|
+
lines.push(`${indentation}skills: () => [`);
|
|
99
|
+
for (const skill of agentData.skills) {
|
|
100
|
+
const parts = [`id: ${formatString(skill.id, q)}`];
|
|
101
|
+
parts.push(`index: ${skill.index}`);
|
|
102
|
+
if (skill.alwaysLoaded) parts.push(`alwaysLoaded: ${skill.alwaysLoaded}`);
|
|
103
|
+
lines.push(`${indentation}${indentation}{ ${parts.join(", ")} },`);
|
|
104
|
+
}
|
|
105
|
+
lines.push(`${indentation}],`);
|
|
106
|
+
}
|
|
97
107
|
if (agentData.canUse && Array.isArray(agentData.canUse) && agentData.canUse.length > 0) {
|
|
98
108
|
const toolReferences = [];
|
|
99
109
|
if (!registry) throw new Error("Registry is required for canUse generation");
|
|
@@ -48,7 +48,8 @@ function createProjectStructure(projectDir) {
|
|
|
48
48
|
environmentsDir: join(projectRoot, "environments"),
|
|
49
49
|
credentialsDir: join(projectRoot, "credentials"),
|
|
50
50
|
contextConfigsDir: join(projectRoot, "context-configs"),
|
|
51
|
-
externalAgentsDir: join(projectRoot, "external-agents")
|
|
51
|
+
externalAgentsDir: join(projectRoot, "external-agents"),
|
|
52
|
+
skillsDir: join(projectRoot, "skills")
|
|
52
53
|
};
|
|
53
54
|
Object.values(paths).forEach((dir) => {
|
|
54
55
|
if (!existsSync(dir)) mkdirSync(dir, { recursive: true });
|
|
@@ -229,6 +230,10 @@ async function pullV3Command(options) {
|
|
|
229
230
|
return;
|
|
230
231
|
}
|
|
231
232
|
const paths = createProjectStructure(projectDir);
|
|
233
|
+
if (remoteProject.skills && Object.keys(remoteProject.skills).length) {
|
|
234
|
+
const { generateSkills } = await import("./components/skill-generator.js");
|
|
235
|
+
await generateSkills(remoteProject.skills, paths.skillsDir);
|
|
236
|
+
}
|
|
232
237
|
if (options.introspect) {
|
|
233
238
|
console.log(chalk.yellow("\nš Introspect mode: Regenerating all files from scratch"));
|
|
234
239
|
s.start("Generating all files deterministically...");
|
|
@@ -98,7 +98,8 @@ async function createNewComponents(comparison, remoteProject, localRegistry, pat
|
|
|
98
98
|
environmentsDir: join(paths.projectRoot, tempDirName, "environments"),
|
|
99
99
|
credentialsDir: join(paths.projectRoot, tempDirName, "credentials"),
|
|
100
100
|
contextConfigsDir: join(paths.projectRoot, tempDirName, "context-configs"),
|
|
101
|
-
externalAgentsDir: join(paths.projectRoot, tempDirName, "external-agents")
|
|
101
|
+
externalAgentsDir: join(paths.projectRoot, tempDirName, "external-agents"),
|
|
102
|
+
skillsDir: join(paths.projectRoot, tempDirName, "skills")
|
|
102
103
|
} : paths;
|
|
103
104
|
const actionText = tempDirName ? "Creating component files in temp directory..." : "Creating new component files...";
|
|
104
105
|
console.log(chalk.cyan(`\nš ${actionText}`));
|
|
@@ -293,6 +293,7 @@ function registerAllComponents(project, registry) {
|
|
|
293
293
|
if (project.dataComponents) for (const componentId of Object.keys(project.dataComponents)) registry.register(componentId, "dataComponents", `data-components/${componentId}.ts`);
|
|
294
294
|
if (project.artifactComponents) for (const componentId of Object.keys(project.artifactComponents)) registry.register(componentId, "artifactComponents", `artifact-components/${componentId}.ts`);
|
|
295
295
|
if (project.externalAgents) for (const extAgentId of Object.keys(project.externalAgents)) registry.register(extAgentId, "externalAgents", `external-agents/${extAgentId}.ts`);
|
|
296
|
+
if (project.skills) for (const skillId of Object.keys(project.skills)) registry.register(skillId, "skills", `skills/${skillId}.md`);
|
|
296
297
|
const statusComponents = extractStatusComponents(project);
|
|
297
298
|
for (const statusId of Object.keys(statusComponents)) registry.register(statusId, "statusComponents", `status-components/${statusId}.ts`);
|
|
298
299
|
if (project.agents) for (const agentId of Object.keys(project.agents)) registry.register(agentId, "agents", `agents/${agentId}.ts`);
|
package/dist/index.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
1
2
|
import "./env.js";
|
|
2
3
|
import "./instrumentation.js";
|
|
3
4
|
import { addCommand } from "./commands/add.js";
|
|
@@ -25,7 +26,7 @@ const packageJsonPath = join(dirname(fileURLToPath(import.meta.url)), "..", "pac
|
|
|
25
26
|
const packageJson = JSON.parse(readFileSync(packageJsonPath, "utf-8"));
|
|
26
27
|
const program = new Command();
|
|
27
28
|
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) => {
|
|
29
|
+
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
30
|
await addCommand({
|
|
30
31
|
template,
|
|
31
32
|
...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
|
|
package/dist/utils/config.js
CHANGED
|
@@ -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.
|
|
3
|
+
"version": "0.48.0",
|
|
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.
|
|
44
|
-
"@inkeep/agents-sdk": "^0.
|
|
43
|
+
"@inkeep/agents-core": "^0.48.0",
|
|
44
|
+
"@inkeep/agents-sdk": "^0.48.0"
|
|
45
45
|
},
|
|
46
46
|
"devDependencies": {
|
|
47
47
|
"@types/degit": "^2.8.6",
|