@imbrace/cli 0.2.0 → 0.3.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 +7 -0
- package/dist/commands/docs.d.ts +10 -0
- package/dist/commands/docs.js +39 -0
- package/llms.txt +625 -0
- package/package.json +3 -2
package/README.md
CHANGED
|
@@ -337,6 +337,13 @@ imbrace data-board list-items --board-id <boardId> --json
|
|
|
337
337
|
|
|
338
338
|
For complete CLI reference for coding agents, see [`llms.txt`](./llms.txt).
|
|
339
339
|
|
|
340
|
+
**Tip — one-shot setup for an AI agent:**
|
|
341
|
+
```bash
|
|
342
|
+
imbrace docs > /tmp/imbrace-llms.txt # ~30 KB reference, bundled with the package
|
|
343
|
+
# then feed /tmp/imbrace-llms.txt into your agent's context (Claude Code, Cursor, ...)
|
|
344
|
+
```
|
|
345
|
+
The `imbrace docs` command prints the full `llms.txt` shipped inside the npm package — no network or repo clone needed.
|
|
346
|
+
|
|
340
347
|
---
|
|
341
348
|
|
|
342
349
|
## Project Structure
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { Command } from "@oclif/core";
|
|
2
|
+
export default class Docs extends Command {
|
|
3
|
+
static description: string;
|
|
4
|
+
static examples: string[];
|
|
5
|
+
static flags: {
|
|
6
|
+
path: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
7
|
+
json: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
8
|
+
};
|
|
9
|
+
run(): Promise<void>;
|
|
10
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { Command, Flags } from "@oclif/core";
|
|
2
|
+
import { readFileSync, existsSync } from "node:fs";
|
|
3
|
+
import { fileURLToPath } from "node:url";
|
|
4
|
+
import { dirname, resolve } from "node:path";
|
|
5
|
+
export default class Docs extends Command {
|
|
6
|
+
static description = "Print the bundled llms.txt — a comprehensive command reference designed to be fed into a coding agent's context (Claude, Cursor, ...). Pipe to a file: `imbrace docs > llms.txt`.";
|
|
7
|
+
static examples = [
|
|
8
|
+
"imbrace docs # print full llms.txt to stdout",
|
|
9
|
+
"imbrace docs --path # print absolute path to bundled llms.txt",
|
|
10
|
+
"imbrace docs > /tmp/imbrace-llms.txt # save for an AI agent's context",
|
|
11
|
+
];
|
|
12
|
+
static flags = {
|
|
13
|
+
path: Flags.boolean({ description: "Print only the absolute path to llms.txt (don't print contents)" }),
|
|
14
|
+
json: Flags.boolean({ description: "Output as JSON: { path, content }" }),
|
|
15
|
+
};
|
|
16
|
+
async run() {
|
|
17
|
+
const { flags } = await this.parse(Docs);
|
|
18
|
+
const here = dirname(fileURLToPath(import.meta.url));
|
|
19
|
+
const candidates = [
|
|
20
|
+
resolve(here, "../../llms.txt"),
|
|
21
|
+
resolve(here, "../llms.txt"),
|
|
22
|
+
resolve(here, "../../../llms.txt"),
|
|
23
|
+
];
|
|
24
|
+
const llmsPath = candidates.find((p) => existsSync(p));
|
|
25
|
+
if (!llmsPath) {
|
|
26
|
+
this.error(`llms.txt not found. Looked in:\n${candidates.map((p) => ` - ${p}`).join("\n")}\n\nReinstall the package or fetch from https://github.com/imbraceltd/imbrace-cli/blob/main/llms.txt`);
|
|
27
|
+
}
|
|
28
|
+
if (flags.path && !flags.json) {
|
|
29
|
+
this.log(llmsPath);
|
|
30
|
+
return;
|
|
31
|
+
}
|
|
32
|
+
const content = readFileSync(llmsPath, "utf8");
|
|
33
|
+
if (flags.json) {
|
|
34
|
+
this.log(JSON.stringify({ path: llmsPath, content }, null, 2));
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
37
|
+
this.log(content);
|
|
38
|
+
}
|
|
39
|
+
}
|
package/llms.txt
ADDED
|
@@ -0,0 +1,625 @@
|
|
|
1
|
+
# Imbrace CLI
|
|
2
|
+
|
|
3
|
+
> Imbrace CLI allows coding agents and developers to interact with the Imbrace platform via command line. Imbrace is a CRM platform supporting AI chat assistants, data boards (CRM pipelines), workflows, and more.
|
|
4
|
+
|
|
5
|
+
Things to remember when using Imbrace CLI:
|
|
6
|
+
|
|
7
|
+
- Always run `imbrace login` first. Credentials are stored via the `conf` package — exact path depends on OS:
|
|
8
|
+
- macOS: `~/Library/Preferences/imbrace-nodejs/config.json`
|
|
9
|
+
- Linux: `~/.config/imbrace-nodejs/config.json`
|
|
10
|
+
- Windows: `%APPDATA%\imbrace-nodejs\Config\config.json`
|
|
11
|
+
- If a command returns a 401 error, run `imbrace login` again to refresh credentials.
|
|
12
|
+
- All commands support `--json` flag for machine-readable output — always use `--json` when scripting or using a coding agent.
|
|
13
|
+
- Run `imbrace data-board list --json` first to get Board IDs (`brd_...`) before using other data-board commands.
|
|
14
|
+
- Board items use the format `{ fields: [{ board_field_id, value }] }` — field IDs are fetched automatically in interactive mode.
|
|
15
|
+
- Field types available (16): `ShortText`, `LongText`, `Number`, `Date`, `Email`, `Phone`, `Currency`, `SingleSelection`, `MultipleSelection`, `Checkbox`, `Assignee`, `MultipleAssignee`, `Link`, `Notes`, `Origin`, `Priority`. **Do NOT use `Dropdown`** — backend rejects it (use `SingleSelection` instead).
|
|
16
|
+
- Run `imbrace ai-agent list --json` first to get Agent IDs before using other ai-agent commands.
|
|
17
|
+
|
|
18
|
+
## Authentication
|
|
19
|
+
|
|
20
|
+
- `imbrace login --api-key api_xxx...` — Login with API key (recommended for CI/CD and coding agents)
|
|
21
|
+
- `imbrace login --email user@example.com --password mypass` — Login with email and password
|
|
22
|
+
- `imbrace logout` — Clear saved credentials
|
|
23
|
+
- `imbrace whoami --json` — Verify current authentication status
|
|
24
|
+
|
|
25
|
+
## Built-in commands
|
|
26
|
+
|
|
27
|
+
- `imbrace help [command]` — Show help for any command
|
|
28
|
+
- `imbrace autocomplete [shell]` — Display shell completion install instructions (bash, zsh, fish, powershell)
|
|
29
|
+
- `imbrace --version` — Print CLI version
|
|
30
|
+
|
|
31
|
+
## Data Board Commands
|
|
32
|
+
|
|
33
|
+
- `imbrace data-board list --json` — List all boards and their IDs (`brd_...`)
|
|
34
|
+
- `imbrace data-board create --name "Sales Pipeline" --json` — Create a new board
|
|
35
|
+
- `imbrace data-board create-field <boardId> --name "Company" --type ShortText --json` — Add a field to a board
|
|
36
|
+
- `imbrace data-board create-item <boardId> --fields '[{"board_field_id":"<id>","value":"Acme"}]' --json` — Create a record (Name field is required)
|
|
37
|
+
- `imbrace data-board list-items --board-id <id> --limit 20 --skip 0 --json` — List records with pagination
|
|
38
|
+
- `imbrace data-board list-items --board-id <id> --q "Acme" --json` — Full-text search records
|
|
39
|
+
- `imbrace data-board update-item <boardId> <itemId> --data '[{"key":"<fieldId>","value":"New"}]' --json` — Update a record
|
|
40
|
+
- `imbrace data-board delete-item <boardId> <itemId> --yes --json` — Delete a record
|
|
41
|
+
- `imbrace data-board export-csv --board-id <id> --out ./board.csv` — Export board to CSV file
|
|
42
|
+
|
|
43
|
+
## AI Agent Commands
|
|
44
|
+
|
|
45
|
+
**CRUD:**
|
|
46
|
+
- `imbrace ai-agent list --json` — List all AI agents and their IDs
|
|
47
|
+
- `imbrace ai-agent get <id> --json` — Get details of an AI agent
|
|
48
|
+
- `imbrace ai-agent create --name "Sales Bot" --json` — Create (minimal — defaults to system provider, "Default" model)
|
|
49
|
+
- `imbrace ai-agent create --name "X" --instructions "..." --personality "..." --tone "..." --json` — Create with full Behavior Settings
|
|
50
|
+
- `imbrace ai-agent update <id> --name "New Name" --json` — Update any subset of fields (others preserved via PUT-merge)
|
|
51
|
+
- `imbrace ai-agent update <id> --temperature 0.7 --tone "Casual" --json` — Update Behavior Settings
|
|
52
|
+
- `imbrace ai-agent delete <id> --yes --json` — Delete an AI agent
|
|
53
|
+
|
|
54
|
+
**Discovery (LLM providers/models):**
|
|
55
|
+
- `imbrace ai-agent list-providers --json` — List LLM providers (system + custom). Returns the UUID `provider_id` to pass to `--provider-id`.
|
|
56
|
+
- `imbrace ai-agent list-models --provider-id <id> --json` — List models for a provider. Use `system` for the default provider.
|
|
57
|
+
|
|
58
|
+
**Discovery (Knowledge Hub):**
|
|
59
|
+
- `imbrace ai-agent list-folders [--search <q>] --json` — List Knowledge Hub folders for `--folder-ids`.
|
|
60
|
+
- `imbrace ai-agent list-files --folder-id <id> --json` — List files inside a folder for `--file-ids`.
|
|
61
|
+
|
|
62
|
+
### AI Agent flags
|
|
63
|
+
|
|
64
|
+
`create` and `update` accept the same flags. `update` lets you change any subset; unspecified flags stay unchanged.
|
|
65
|
+
|
|
66
|
+
**Identity:**
|
|
67
|
+
- `--name` / `-n` — Agent name (required for create)
|
|
68
|
+
- `--description` / `-d` — Short description (shown under the title in UI list)
|
|
69
|
+
- `--instructions` / `-i` — System prompt sent on every chat
|
|
70
|
+
|
|
71
|
+
**Model:**
|
|
72
|
+
- `--model` — LLM model name (default: `Default` for system provider). Discover via `list-models`. **System provider only has one model named `Default`** — passing other names (like `gpt-4o`) makes the UI dropdown render empty even though the agent saves.
|
|
73
|
+
- `--provider-id` — LLM provider ID (default: `system`). Discover via `list-providers`. **Pass the UUID `provider_id`, NOT the MongoDB `_id`** — the UI matches dropdowns against the UUID.
|
|
74
|
+
- `--mode` — `standard` | `advanced` (default: standard)
|
|
75
|
+
- `--temperature` — 0.0–2.0 (default: 0.1). Lower = deterministic, higher = creative.
|
|
76
|
+
|
|
77
|
+
**Behavior Settings (UI tab):**
|
|
78
|
+
- `--personality` — Persona / role description → `personality_role`
|
|
79
|
+
- `--core-task` — Main tasks the agent performs → `core_task`
|
|
80
|
+
- `--tone` — Tone and style → `tone_and_style`
|
|
81
|
+
- `--response-length` — `short` | `medium` | `long`
|
|
82
|
+
- `--banned-words` — Comma-separated. **Word-level filter** on outputs (for topic refusal use `--instructions`).
|
|
83
|
+
- `--category` — `Support` | `Sales` | `Marketing` | `Team` | `Other`. Default: `Support`.
|
|
84
|
+
- `--guardrail-id` — Attach a guardrail by ID
|
|
85
|
+
- `--preload-information` — Static info auto-injected into context every chat
|
|
86
|
+
|
|
87
|
+
**Knowledge Support (UI tab) — comma-separated IDs:**
|
|
88
|
+
- `--folder-ids "id1,id2"` — Knowledge Hub folder IDs (RAG sources). Discover via `list-folders`.
|
|
89
|
+
- `--default-folder-id <id>` — Default folder for new files
|
|
90
|
+
- `--knowledge-hubs "id1,id2"` — Knowledge Hub IDs
|
|
91
|
+
- `--board-ids "brd_xxx,brd_yyy"` — Document Model (data board) IDs. Discover via `imbrace data-board list`.
|
|
92
|
+
- `--file-ids "id1,id2"` — Pre-uploaded file IDs. Discover via `list-files --folder-id <id>`.
|
|
93
|
+
|
|
94
|
+
**Runtime toggles (boolean, support `--no-X`):**
|
|
95
|
+
- `--show-thinking` / `--no-show-thinking` — Show model's thinking process (default: false)
|
|
96
|
+
- `--streaming` / `--no-streaming` — Stream response token-by-token (default: true)
|
|
97
|
+
- `--use-memory` / `--no-use-memory` — Remember conversation context across turns (default: true). **Known issue:** `--no-use-memory` at create may not stick (backend default override) — workaround: update after create.
|
|
98
|
+
|
|
99
|
+
**Other:**
|
|
100
|
+
- `--yes` / `-y` — Skip confirmation on delete
|
|
101
|
+
- `--json` — Full JSON output (machine-readable)
|
|
102
|
+
- `--id-only` — Print only the new agent ID (pipe-friendly, no jq). On `create` only.
|
|
103
|
+
- `-h` / `--help` — Show usage
|
|
104
|
+
|
|
105
|
+
### Full create example (Behavior Settings + custom provider + Knowledge)
|
|
106
|
+
|
|
107
|
+
```bash
|
|
108
|
+
# 1. Discover provider + model
|
|
109
|
+
imbrace ai-agent list-providers --json
|
|
110
|
+
imbrace ai-agent list-models --provider-id e2629292-7e9f-4d55-ba18-6827747eab33 --json
|
|
111
|
+
|
|
112
|
+
# 2. Discover Knowledge Hub folder + board (Document Model)
|
|
113
|
+
imbrace ai-agent list-folders --search support --json
|
|
114
|
+
imbrace data-board list --json
|
|
115
|
+
|
|
116
|
+
# 3. Create with full settings
|
|
117
|
+
imbrace ai-agent create \
|
|
118
|
+
--name "Customer Support Specialist" \
|
|
119
|
+
--description "Senior AI customer support agent" \
|
|
120
|
+
--instructions "You are a senior customer support specialist..." \
|
|
121
|
+
--personality "Friendly and professional" \
|
|
122
|
+
--core-task "Answer product inquiries, help track orders" \
|
|
123
|
+
--tone "Polite, professional, warm" \
|
|
124
|
+
--response-length "medium" \
|
|
125
|
+
--banned-words "stupid, idiot" \
|
|
126
|
+
--category "Support" \
|
|
127
|
+
--provider-id "e2629292-7e9f-4d55-ba18-6827747eab33" \
|
|
128
|
+
--model "gpt-4o-mini" \
|
|
129
|
+
--temperature 0.3 \
|
|
130
|
+
--folder-ids "69bb82faa2cc764639bc6bdb" \
|
|
131
|
+
--board-ids "brd_e5450d76-84d4-4c34-8b13-3d0f1873b53b" \
|
|
132
|
+
--json
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
### How AI Agent create works (under the hood)
|
|
136
|
+
|
|
137
|
+
`imbrace ai-agent create` calls `client.agent.createUseCase({ usecase, assistant })` from `@imbrace/sdk`, which atomically creates:
|
|
138
|
+
1. An AI assistant (model, instructions, prompt)
|
|
139
|
+
2. A web channel (for chat widget demo)
|
|
140
|
+
3. A use-case template (the card shown on `cloud.imbrace.co/ai-agent`)
|
|
141
|
+
|
|
142
|
+
The `workflow_name` field is auto-generated as `<slug>_v<timestamp>` to ensure uniqueness — required by backend, must be snake_case (no spaces or special characters).
|
|
143
|
+
|
|
144
|
+
### Full request body sent to backend
|
|
145
|
+
|
|
146
|
+
The route mirrors the frontend `createCustomUseCase` payload (see `new-frontend/src/pages/AIAssistantManagement/useAIAssistantFormHook.tsx`):
|
|
147
|
+
|
|
148
|
+
```ts
|
|
149
|
+
{
|
|
150
|
+
usecase: { title, short_description, agent_type, demo_url, supported_channels },
|
|
151
|
+
assistant: {
|
|
152
|
+
// Identity
|
|
153
|
+
name, description, instructions, workflow_name, credential_name,
|
|
154
|
+
// Model
|
|
155
|
+
provider_id: "system", model_id: "gpt-4o",
|
|
156
|
+
// Agent scope
|
|
157
|
+
agent_type: "agent", mode: "standard", version: 2, channel, category,
|
|
158
|
+
// Behavior (Behavior Settings tab in UI)
|
|
159
|
+
personality_role, core_task, tone_and_style, response_length,
|
|
160
|
+
banned_words, preload_information, guardrail_id, show_thinking_process,
|
|
161
|
+
// Runtime
|
|
162
|
+
streaming: true, use_memory: true, temperature: 0.1,
|
|
163
|
+
// Knowledge (Knowledge Support tab in UI)
|
|
164
|
+
knowledge_hubs: [], folder_ids: [], default_folder_id, board_ids: [], file_ids: [],
|
|
165
|
+
// Advanced (Advanced Settings tab in UI)
|
|
166
|
+
workflow_function_call: [], sub_agents: [], team_leads: [],
|
|
167
|
+
// RAG / tooling
|
|
168
|
+
metadata: {
|
|
169
|
+
other_requirements: [], channel_id: "", team_ids: [], tool_server: null,
|
|
170
|
+
enable_echart: false, top_k_relevant_results: 3, top_k: 40, max_steps: 10
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
**Fields not yet exposed via CLI flags** (set to defaults — modify via UI or future CLI updates): `channel`, `preload_information`, `knowledge_hubs`, `folder_ids`, `default_folder_id`, `board_ids`, `file_ids`, `workflow_function_call`, `sub_agents`, `team_leads`, `metadata.tool_server`, `metadata.team_ids`, `metadata.other_requirements`.
|
|
177
|
+
|
|
178
|
+
**IMPORTANT — All AI Agent content must be in English.** This includes `--name`, `--description`, and `--instructions`. Reasons:
|
|
179
|
+
1. The slug for `workflow_name` is derived from the name. Vietnamese diacritics get stripped and produce unreadable slugs (e.g. `"Trợ lý hỗ trợ"` → `tr_l_h_tr_v...`).
|
|
180
|
+
2. English content keeps logs, search, and downstream LLM behavior consistent.
|
|
181
|
+
|
|
182
|
+
If the user describes an agent in Vietnamese, translate the full payload to English before calling `imbrace ai-agent create`.
|
|
183
|
+
|
|
184
|
+
## Workflow Commands
|
|
185
|
+
|
|
186
|
+
A workflow (powered by Activepieces) is a chain of nodes: a trigger fires, then actions run in sequence. Use it for automation — e.g. "when Slack message arrives → ask AI → reply to thread".
|
|
187
|
+
|
|
188
|
+
**Flow CRUD:**
|
|
189
|
+
|
|
190
|
+
- `imbrace workflow list --json` — List all workflows and their IDs
|
|
191
|
+
- `imbrace workflow list --folder-id <folderId> --json` — Filter to flows in one folder/category
|
|
192
|
+
- `imbrace workflow list --folder-id NULL --json` — Only flows that aren't in any folder
|
|
193
|
+
- `imbrace workflow get <flowId> --json` — Get details (including node tree)
|
|
194
|
+
- `imbrace workflow create --name "My Flow" --json` — Create an empty workflow
|
|
195
|
+
- `imbrace workflow create --name "X" --folder-id <folderId> --json` — Create directly inside a category folder
|
|
196
|
+
- `imbrace workflow move <flowId> --folder-id <folderId>` — Move a flow into a folder. Pass `NULL` to unfile.
|
|
197
|
+
- `imbrace workflow delete <flowId> --yes --json` — Delete a workflow
|
|
198
|
+
|
|
199
|
+
**Discover available integrations (pieces):**
|
|
200
|
+
|
|
201
|
+
- `imbrace workflow piece list --json` — List all 126 integrations (Slack, Gmail, OpenAI, ...)
|
|
202
|
+
- `imbrace workflow piece list --search slack --json` — Search integrations
|
|
203
|
+
- `imbrace workflow piece detail <pieceName> --json` — Get full schema (actions, triggers, input fields)
|
|
204
|
+
|
|
205
|
+
**Build node tree:**
|
|
206
|
+
|
|
207
|
+
- `imbrace workflow node list <flowId> --json` — Show the trigger + action chain
|
|
208
|
+
- `imbrace workflow node add <flowId> --type trigger --piece <name> --trigger-name <id> --input '{...}' --json` — Add trigger
|
|
209
|
+
- `imbrace workflow node add <flowId> --type action --piece <name> --action-name <id> --after <parent> --input '{...}' --json` — Add action
|
|
210
|
+
- `imbrace workflow node update <flowId> <nodeName> --input '{...}' --json` — Update node input
|
|
211
|
+
- `imbrace workflow node delete <flowId> <nodeName> --yes --json` — Remove a node
|
|
212
|
+
- `imbrace workflow node add-raw <flowId> --op-file <path>` — Apply raw flow operation. Use for advanced node types (`ROUTER`, `LOOP_ON_ITEMS`, `CODE`) that `node add` doesn't expose. Body shape: `{ type: "ADD_ACTION" \| "UPDATE_ACTION" \| "UPDATE_TRIGGER" \| "DELETE_ACTION", request: {...} }`. Also accepts `--op '<inline JSON>'` or `--stdin`.
|
|
213
|
+
|
|
214
|
+
**Run history:**
|
|
215
|
+
|
|
216
|
+
- `imbrace workflow runs --json` — List recent runs
|
|
217
|
+
- `imbrace workflow run-detail <runId> --json` — Get run details (status, failed step, logs)
|
|
218
|
+
|
|
219
|
+
**Connections (OAuth / API keys for external services):**
|
|
220
|
+
|
|
221
|
+
- `imbrace workflow conn list --json` — List saved connections
|
|
222
|
+
- `imbrace workflow conn get <connId> --json` — Get details of a single connection
|
|
223
|
+
- `imbrace workflow conn create --piece <name> --type <T> --value "<token>" --json` — Save credential. `--type`: `SECRET_TEXT` | `OAUTH2` | `CLOUD_OAUTH2` | `BASIC_AUTH` | `CUSTOM_AUTH`
|
|
224
|
+
- `imbrace workflow conn delete <connId> --yes` — Delete a connection
|
|
225
|
+
|
|
226
|
+
**Folders (organize flows — UI calls them "Categories"):**
|
|
227
|
+
|
|
228
|
+
- `imbrace workflow folder list --json` — List all folders
|
|
229
|
+
- `imbrace workflow folder get <folderId> --json` — Folder details
|
|
230
|
+
- `imbrace workflow folder create --name "Sales" --json` — Create (auto-resolves projectId)
|
|
231
|
+
- `imbrace workflow folder update <folderId> --name "Renamed" --json` — Rename
|
|
232
|
+
- `imbrace workflow folder delete <folderId> --yes` — Delete (flows inside become unfiled, NOT deleted)
|
|
233
|
+
|
|
234
|
+
The platform auto-creates 4 system folders that show up as Categories in the UI. Use `workflow folder list` to discover their IDs:
|
|
235
|
+
|
|
236
|
+
| UI Category | Backend folder name | Purpose |
|
|
237
|
+
|---|---|---|
|
|
238
|
+
| `Channel Workflow` | `Channel Workflow` | Messaging / channel automation |
|
|
239
|
+
| `Board Automation` | `Board Automation` | Triggered by data-board events; flows usually use the `automate-data-board` action with a `boardId` |
|
|
240
|
+
| `AI Agent Skills` | `AI Agent Capabilities` | Skills callable by AI agents |
|
|
241
|
+
| `Others` | `Others` | Default catch-all |
|
|
242
|
+
|
|
243
|
+
To make a flow appear in a UI Category, place it in the matching system folder via `workflow create --folder-id <id>` or `workflow move <flowId> --folder-id <id>`. Flows created with no folder land in "All flows" only (not in any Category).
|
|
244
|
+
|
|
245
|
+
**MCP servers (Model Context Protocol — let AI agents call piece tools):**
|
|
246
|
+
|
|
247
|
+
- `imbrace workflow mcp list --json` — List MCP servers for the project
|
|
248
|
+
- `imbrace workflow mcp get <mcpId> --json` — Server details (token NOT shown for security)
|
|
249
|
+
- `imbrace workflow mcp create --name "My MCP" --json` — Create. **Token is shown once at creation — save it immediately.**
|
|
250
|
+
- `imbrace workflow mcp rotate-token <mcpId> --yes` — Issue a new token. Old token stops working immediately.
|
|
251
|
+
- `imbrace workflow mcp delete <mcpId> --yes` — Delete the server
|
|
252
|
+
|
|
253
|
+
**Lifecycle:**
|
|
254
|
+
|
|
255
|
+
- `imbrace workflow publish <flowId>` — Lock current draft as published version (REQUIRED before enable)
|
|
256
|
+
- `imbrace workflow enable <flowId>` — Enable auto-trigger
|
|
257
|
+
- `imbrace workflow disable <flowId>` — Stop auto-trigger (keeps published version)
|
|
258
|
+
|
|
259
|
+
**Trigger flow manually:**
|
|
260
|
+
|
|
261
|
+
- `imbrace workflow run <flowId> --payload '{...}' --json` — Trigger async (fire-and-forget)
|
|
262
|
+
- `imbrace workflow run <flowId> --payload '{...}' --sync --json` — Trigger and wait. ⚠️ Sync polling may time out at ~30s even when the run finishes faster — fall back to `imbrace workflow runs` + `run-detail <runId>` to verify.
|
|
263
|
+
|
|
264
|
+
**Order matters:** create flow → add nodes → **publish** → **enable** → run. Trying to `enable` before `publish` returns 500 "publishedFlowVersionId is required".
|
|
265
|
+
|
|
266
|
+
### Workflow flags
|
|
267
|
+
|
|
268
|
+
**Flow-level:**
|
|
269
|
+
- `--name` / `-n` — Workflow display name (required for create)
|
|
270
|
+
- `--folder-id` — Folder to place flow in
|
|
271
|
+
- `--yes` / `-y` — Skip confirmation on delete
|
|
272
|
+
- `--json` — Machine-readable output
|
|
273
|
+
|
|
274
|
+
**Node-level:**
|
|
275
|
+
- `--type` — `trigger` or `action`
|
|
276
|
+
- `--piece` — Piece name (e.g. `@activepieces/piece-slack`)
|
|
277
|
+
- `--trigger-name` — Trigger identifier from piece (when `--type trigger`)
|
|
278
|
+
- `--action-name` — Action identifier from piece (when `--type action`)
|
|
279
|
+
- `--after` — Place node after this step name (default: append at end)
|
|
280
|
+
- `--input` — JSON string with field values (use `{{trigger.X}}` or `{{step_N.output.Y}}` for variables)
|
|
281
|
+
- `--connection` — Connection ID to authenticate the piece
|
|
282
|
+
|
|
283
|
+
**Run flags:**
|
|
284
|
+
- `--payload` — JSON payload to send (becomes `trigger.body` in flow)
|
|
285
|
+
- `--sync` — Wait for flow to finish (timeout 60s); without it, fire-and-forget
|
|
286
|
+
- `--limit` — Max runs to list (default 10)
|
|
287
|
+
|
|
288
|
+
### How Workflow create works (under the hood)
|
|
289
|
+
|
|
290
|
+
`imbrace workflow create` calls `client.activepieces.createFlow({ displayName, projectId })`. The route auto-discovers `projectId` from existing flows so the user doesn't pass it.
|
|
291
|
+
|
|
292
|
+
Adding/editing nodes calls `client.activepieces.applyFlowOperation(flowId, { type, request })` with operation types:
|
|
293
|
+
- `UPDATE_TRIGGER` — replace trigger node
|
|
294
|
+
- `ADD_ACTION` — add an action after a parent step
|
|
295
|
+
- `UPDATE_ACTION` — change input of an existing action
|
|
296
|
+
- `DELETE_ACTION` — remove a node and re-link parent → child
|
|
297
|
+
- `LOCK_AND_PUBLISH` — finalize current version (used by `workflow publish`)
|
|
298
|
+
- `CHANGE_STATUS` — toggle ENABLED/DISABLED (used by `workflow enable/disable`)
|
|
299
|
+
|
|
300
|
+
Piece schemas (`piece detail`) come from a raw `GET /activepieces/v1/pieces/<pieceName>` because SDK's `listPieces()` only returns counts (`actions: 25`, `triggers: 12`), not field schemas.
|
|
301
|
+
|
|
302
|
+
### Flow JSON anatomy
|
|
303
|
+
|
|
304
|
+
A workflow stores its node tree under `version.trigger`, with `nextAction` linking the chain:
|
|
305
|
+
|
|
306
|
+
```ts
|
|
307
|
+
{
|
|
308
|
+
id: "06oWoBQpL...",
|
|
309
|
+
status: "ENABLED" | "DISABLED",
|
|
310
|
+
version: {
|
|
311
|
+
displayName: "My Flow",
|
|
312
|
+
trigger: {
|
|
313
|
+
name: "trigger",
|
|
314
|
+
type: "PIECE_TRIGGER", // or BRANCH, LOOP_ON_ITEMS, CODE
|
|
315
|
+
settings: { pieceName, triggerName, input },
|
|
316
|
+
nextAction: {
|
|
317
|
+
name: "step_1",
|
|
318
|
+
type: "PIECE",
|
|
319
|
+
settings: { pieceName, actionName, input },
|
|
320
|
+
nextAction: { name: "step_2", ... }
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
```
|
|
326
|
+
|
|
327
|
+
### Variable syntax inside node `input`
|
|
328
|
+
|
|
329
|
+
- `{{trigger.body.X}}` — field X from trigger payload
|
|
330
|
+
- `{{trigger.X}}` — top-level trigger field (for piece triggers)
|
|
331
|
+
- `{{step_1.output.Y}}` — output field Y from step_1
|
|
332
|
+
- `{{connections.<connId>.access_token}}` — connection field
|
|
333
|
+
|
|
334
|
+
### Workflow anatomy — 6 layers
|
|
335
|
+
|
|
336
|
+
```
|
|
337
|
+
Project
|
|
338
|
+
└─ Flow (container — id, name, status: ENABLED/DISABLED)
|
|
339
|
+
└─ Version (snapshot — DRAFT or LOCKED, contains the node tree)
|
|
340
|
+
└─ Nodes (cây trigger + actions, linked via nextAction)
|
|
341
|
+
├─ trigger (always 1, type PIECE_TRIGGER or EMPTY)
|
|
342
|
+
└─ step_1, step_2, ... (0..N actions)
|
|
343
|
+
└─ Runs (execution history — status, logs per run)
|
|
344
|
+
|
|
345
|
+
Cross-flow shared:
|
|
346
|
+
├─ Connections (OAuth / API keys, reused across flows)
|
|
347
|
+
└─ Pieces (catalog of 126 integrations: Slack, Gmail, OpenAI, ...)
|
|
348
|
+
```
|
|
349
|
+
|
|
350
|
+
### Node types
|
|
351
|
+
|
|
352
|
+
A node's `type` field determines its role in the flow:
|
|
353
|
+
|
|
354
|
+
| Type | Role | CLI support |
|
|
355
|
+
|---|---|---|
|
|
356
|
+
| `PIECE_TRIGGER` | "When does the flow run" — Slack message, webhook, cron, ... | ✅ `node add --type trigger` |
|
|
357
|
+
| `PIECE` | "What runs after" — send Slack, ask AI, HTTP request, ... | ✅ `node add --type action` |
|
|
358
|
+
| `EMPTY` | Placeholder before a real trigger is set (default after `workflow create`) | ✅ Read-only |
|
|
359
|
+
| `ROUTER` | Multi-condition switch (replaces legacy BRANCH) | ✅ `node add-raw` |
|
|
360
|
+
| `LOOP_ON_ITEMS` | Loop over an array | ✅ `node add-raw` |
|
|
361
|
+
| `CODE` | Inline JavaScript | ✅ `node add-raw` |
|
|
362
|
+
|
|
363
|
+
Most flows use only `PIECE_TRIGGER` + `PIECE`. For the other 3 types use `node add-raw` with a full Activepieces operation payload — see shapes below.
|
|
364
|
+
|
|
365
|
+
**Constraints when composing advanced nodes:**
|
|
366
|
+
1. `LOOP_ON_ITEMS` and `CODE` must have a `parentStep` of type `trigger` or `PIECE`. Setting parent to a `ROUTER` (or another LOOP) returns 400 `Router step parent undefined not found`. To put a LOOP/CODE inside a router branch, build the inner action as part of the ROUTER's `children` array, not as a separate ADD_ACTION.
|
|
367
|
+
2. `node list` only walks the linear `trigger → nextAction → nextAction` chain. Children of `ROUTER` (in `children: []`) and the body of `LOOP_ON_ITEMS` (in `firstLoopAction`) are stored server-side but not displayed by the flat list. Use `workflow get <flowId> --json` to see the full nested tree.
|
|
368
|
+
|
|
369
|
+
**Gotchas when updating live flows:**
|
|
370
|
+
- **Flow lock** — if the user has the flow open in their browser, CLI updates may be rejected with `"edited at the last minute, try again later"` or silently overwritten when the UI auto-saves. Ask the user to close the flow editor tab before bulk-updating via CLI; verify with `workflow get --json` that your changes stuck.
|
|
371
|
+
- **AI Connector `assistant-request` prompt field** — the `prompt` input is a NESTED object, not a plain string. The UI form binds to `input.prompt.prompt`. Plain string values like `input.prompt = "text"` are accepted by the API but the UI renders the field as empty. Always send `{ "prompt": { "prompt": "actual text" } }`. The separate `custom_instructions` field IS a plain string and maps to the UI's "Custom Instructions" section.
|
|
372
|
+
|
|
373
|
+
### Raw operation shapes for advanced nodes
|
|
374
|
+
|
|
375
|
+
For `ROUTER`, `LOOP_ON_ITEMS`, `CODE` use `imbrace workflow node add-raw <flowId> --op-file <path>`. The op file contains `{ type, request }` — the full Activepieces flow-operation body. Examples:
|
|
376
|
+
|
|
377
|
+
**ROUTER** — multi-condition switch:
|
|
378
|
+
```json
|
|
379
|
+
{
|
|
380
|
+
"type": "ADD_ACTION",
|
|
381
|
+
"request": {
|
|
382
|
+
"parentStep": "trigger",
|
|
383
|
+
"action": {
|
|
384
|
+
"name": "step_1",
|
|
385
|
+
"type": "ROUTER",
|
|
386
|
+
"displayName": "Check priority",
|
|
387
|
+
"settings": {
|
|
388
|
+
"branches": [
|
|
389
|
+
{
|
|
390
|
+
"branchName": "High",
|
|
391
|
+
"branchType": "CONDITION",
|
|
392
|
+
"conditions": [[{
|
|
393
|
+
"operator": "TEXT_EXACTLY_MATCHES",
|
|
394
|
+
"firstValue": "{{trigger.body.priority}}",
|
|
395
|
+
"secondValue": "high",
|
|
396
|
+
"caseSensitive": false
|
|
397
|
+
}]]
|
|
398
|
+
},
|
|
399
|
+
{ "branchName": "Default", "branchType": "FALLBACK" }
|
|
400
|
+
],
|
|
401
|
+
"executionType": "EXECUTE_FIRST_MATCH",
|
|
402
|
+
"sampleData": {}
|
|
403
|
+
},
|
|
404
|
+
"children": [null, null],
|
|
405
|
+
"valid": true
|
|
406
|
+
}
|
|
407
|
+
}
|
|
408
|
+
}
|
|
409
|
+
```
|
|
410
|
+
|
|
411
|
+
**LOOP_ON_ITEMS** — loop over an array. `parentStep` must be a `trigger` or `PIECE` (not a ROUTER):
|
|
412
|
+
```json
|
|
413
|
+
{
|
|
414
|
+
"type": "ADD_ACTION",
|
|
415
|
+
"request": {
|
|
416
|
+
"parentStep": "trigger",
|
|
417
|
+
"action": {
|
|
418
|
+
"name": "step_1",
|
|
419
|
+
"type": "LOOP_ON_ITEMS",
|
|
420
|
+
"displayName": "Loop users",
|
|
421
|
+
"settings": { "items": "{{trigger.body.users}}" },
|
|
422
|
+
"firstLoopAction": null,
|
|
423
|
+
"valid": true
|
|
424
|
+
}
|
|
425
|
+
}
|
|
426
|
+
}
|
|
427
|
+
```
|
|
428
|
+
|
|
429
|
+
**CODE** — inline JavaScript:
|
|
430
|
+
```json
|
|
431
|
+
{
|
|
432
|
+
"type": "ADD_ACTION",
|
|
433
|
+
"request": {
|
|
434
|
+
"parentStep": "step_1",
|
|
435
|
+
"action": {
|
|
436
|
+
"name": "step_2",
|
|
437
|
+
"type": "CODE",
|
|
438
|
+
"displayName": "Transform",
|
|
439
|
+
"settings": {
|
|
440
|
+
"input": { "x": "{{trigger.body.value}}" },
|
|
441
|
+
"sourceCode": {
|
|
442
|
+
"code": "export const code = async (inputs) => ({ doubled: inputs.x * 2 });",
|
|
443
|
+
"packageJson": "{\"dependencies\":{}}"
|
|
444
|
+
}
|
|
445
|
+
},
|
|
446
|
+
"valid": true
|
|
447
|
+
}
|
|
448
|
+
}
|
|
449
|
+
}
|
|
450
|
+
```
|
|
451
|
+
|
|
452
|
+
**Common operation types** for `add-raw`:
|
|
453
|
+
- `ADD_ACTION` — add a new node (with `parentStep` + `action` shape above)
|
|
454
|
+
- `UPDATE_ACTION` — replace an existing node's settings (request: `{ name, type, displayName, settings, valid }`)
|
|
455
|
+
- `UPDATE_TRIGGER` — replace the trigger node
|
|
456
|
+
- `DELETE_ACTION` — remove a node (request: `{ names: ["step_X"] }`)
|
|
457
|
+
|
|
458
|
+
### Connection types
|
|
459
|
+
|
|
460
|
+
When calling `workflow conn create --type <X>` (Sprint 3), valid types are:
|
|
461
|
+
|
|
462
|
+
| Type | Use case |
|
|
463
|
+
|---|---|
|
|
464
|
+
| `SECRET_TEXT` | Simple API key (Slack bot token, OpenAI key) |
|
|
465
|
+
| `OAUTH2` | OAuth flow with custom app (Google, Slack OAuth) |
|
|
466
|
+
| `CLOUD_OAUTH2` | OAuth via Activepieces hosted apps (no custom app setup needed) |
|
|
467
|
+
| `BASIC_AUTH` | username + password |
|
|
468
|
+
| `CUSTOM_AUTH` | Custom format defined by the piece |
|
|
469
|
+
|
|
470
|
+
Use `imbrace workflow piece detail <pieceName>` to see which auth type a piece accepts.
|
|
471
|
+
|
|
472
|
+
### Workflow lifecycle
|
|
473
|
+
|
|
474
|
+
```
|
|
475
|
+
DRAFT (editing) → publish → LOCKED (production) → enable → ENABLED (auto-running)
|
|
476
|
+
↑
|
|
477
|
+
disable (back to DISABLED but still LOCKED)
|
|
478
|
+
```
|
|
479
|
+
|
|
480
|
+
- `workflow publish` locks the current draft version and marks it as the production version.
|
|
481
|
+
- `workflow enable` turns on auto-trigger — fires the flow whenever its trigger condition is met.
|
|
482
|
+
- `workflow disable` stops auto-trigger but keeps the published version intact.
|
|
483
|
+
- Edit after publish: backend creates a new DRAFT version; previous LOCKED version keeps running until you publish the new draft.
|
|
484
|
+
|
|
485
|
+
## Setup
|
|
486
|
+
|
|
487
|
+
```bash
|
|
488
|
+
# 1. Start the API
|
|
489
|
+
cd api && bun install && bun run dev
|
|
490
|
+
|
|
491
|
+
# 2. Install the CLI (one-shot — handles build, link, and cross-shell PATH)
|
|
492
|
+
cd .. && ./install.sh
|
|
493
|
+
|
|
494
|
+
# 3. Login
|
|
495
|
+
imbrace login --api-key api_xxx...
|
|
496
|
+
|
|
497
|
+
# 4. Verify
|
|
498
|
+
imbrace whoami --json
|
|
499
|
+
```
|
|
500
|
+
|
|
501
|
+
The `install.sh` script symlinks `imbrace` into `/opt/homebrew/bin` (Apple Silicon) or `/usr/local/bin` so the command works even from shells that don't load nvm — for example conda's `(base)` env.
|
|
502
|
+
|
|
503
|
+
## Quick Start for Coding Agents
|
|
504
|
+
|
|
505
|
+
### Data Board
|
|
506
|
+
```bash
|
|
507
|
+
# Get available boards
|
|
508
|
+
imbrace data-board list --json
|
|
509
|
+
|
|
510
|
+
# Create a board
|
|
511
|
+
imbrace data-board create --name "Leads" --json
|
|
512
|
+
|
|
513
|
+
# Add a field
|
|
514
|
+
imbrace data-board create-field <boardId> --name "Company" --type ShortText --json
|
|
515
|
+
|
|
516
|
+
# Add a record (Name field is required — use its field ID)
|
|
517
|
+
imbrace data-board create-item <boardId> --fields '[{"board_field_id":"<nameFieldId>","value":"John Doe"},{"board_field_id":"<fieldId>","value":"Acme Corp"}]' --json
|
|
518
|
+
|
|
519
|
+
# List records
|
|
520
|
+
imbrace data-board list-items --board-id <boardId> --json
|
|
521
|
+
|
|
522
|
+
# Export to CSV
|
|
523
|
+
imbrace data-board export-csv --board-id <boardId> --out ./leads.csv
|
|
524
|
+
```
|
|
525
|
+
|
|
526
|
+
### AI Agent
|
|
527
|
+
```bash
|
|
528
|
+
# Discover what's available
|
|
529
|
+
imbrace ai-agent list --json
|
|
530
|
+
imbrace ai-agent list-providers --json
|
|
531
|
+
imbrace ai-agent list-models --provider-id system --json
|
|
532
|
+
imbrace ai-agent list-folders --json
|
|
533
|
+
|
|
534
|
+
# Create an agent (minimal)
|
|
535
|
+
imbrace ai-agent create --name "Sales Bot" --instructions "You are a sales assistant" --json
|
|
536
|
+
|
|
537
|
+
# Create with custom provider + Knowledge Hub folder
|
|
538
|
+
imbrace ai-agent create --name "RAG Bot" \
|
|
539
|
+
--instructions "Answer using the provided knowledge" \
|
|
540
|
+
--provider-id e2629292-7e9f-4d55-ba18-6827747eab33 \
|
|
541
|
+
--model gpt-4o-mini \
|
|
542
|
+
--folder-ids 69bb82faa2cc764639bc6bdb \
|
|
543
|
+
--json
|
|
544
|
+
|
|
545
|
+
# Update — partial (other fields preserved)
|
|
546
|
+
imbrace ai-agent update <agentId> --instructions "Updated" --temperature 0.7 --json
|
|
547
|
+
|
|
548
|
+
# Delete
|
|
549
|
+
imbrace ai-agent delete <agentId> --yes --json
|
|
550
|
+
```
|
|
551
|
+
|
|
552
|
+
### Workflow — build a Slack auto-reply bot end-to-end
|
|
553
|
+
|
|
554
|
+
**Note:** Steps 1, 3, 4, 5, 6, 7 use Sprint 1+2 commands (already implemented).
|
|
555
|
+
Steps 2, 8, 9 use Sprint 3 commands (**not yet implemented** — for now, do them via the [UI builder](https://cloud.imbrace.co/workflow-v2)).
|
|
556
|
+
|
|
557
|
+
```bash
|
|
558
|
+
# 1. Discover Slack + AI integrations (schemas) ✅ Sprint 2
|
|
559
|
+
imbrace workflow piece list --search slack --json
|
|
560
|
+
imbrace workflow piece detail @activepieces/piece-slack --json
|
|
561
|
+
imbrace workflow piece detail @activepieces/piece-ai-connector --json
|
|
562
|
+
|
|
563
|
+
# 2. Save Slack token (one-time per workspace) ✅ Sprint 3
|
|
564
|
+
imbrace workflow conn create \
|
|
565
|
+
--piece @activepieces/piece-slack \
|
|
566
|
+
--type SECRET_TEXT \
|
|
567
|
+
--value "xoxb-actual-token" \
|
|
568
|
+
--json
|
|
569
|
+
# → note conn._id
|
|
570
|
+
|
|
571
|
+
# 3. Create empty flow ✅ Sprint 1
|
|
572
|
+
imbrace workflow create --name "Slack AI Reply Bot" --json
|
|
573
|
+
# → note flow._id
|
|
574
|
+
|
|
575
|
+
# 4. Add Slack trigger (catch new messages) ✅ Sprint 2
|
|
576
|
+
imbrace workflow node add <flowId> \
|
|
577
|
+
--type trigger \
|
|
578
|
+
--piece @activepieces/piece-slack \
|
|
579
|
+
--trigger-name new_message_in_channel \
|
|
580
|
+
--connection <connId> \
|
|
581
|
+
--input '{"channel":"C0XXXXX"}' \
|
|
582
|
+
--json
|
|
583
|
+
|
|
584
|
+
# 5. Add AI action (draft a reply) ✅ Sprint 2
|
|
585
|
+
imbrace workflow node add <flowId> \
|
|
586
|
+
--type action \
|
|
587
|
+
--piece @activepieces/piece-ai-connector \
|
|
588
|
+
--action-name ask \
|
|
589
|
+
--after trigger \
|
|
590
|
+
--input '{"modelName":"gpt-4o","prompt":"Draft a friendly reply to: {{trigger.text}}"}' \
|
|
591
|
+
--json
|
|
592
|
+
|
|
593
|
+
# 6. Add Slack reply (post answer back to thread) ✅ Sprint 2
|
|
594
|
+
imbrace workflow node add <flowId> \
|
|
595
|
+
--type action \
|
|
596
|
+
--piece @activepieces/piece-slack \
|
|
597
|
+
--action-name send_channel_message \
|
|
598
|
+
--after step_1 \
|
|
599
|
+
--connection <connId> \
|
|
600
|
+
--input '{"channel":"{{trigger.channel}}","text":"{{step_1.output.text}}","thread_ts":"{{trigger.ts}}"}' \
|
|
601
|
+
--json
|
|
602
|
+
|
|
603
|
+
# 7. Verify the node tree ✅ Sprint 2
|
|
604
|
+
imbrace workflow node list <flowId> --json
|
|
605
|
+
|
|
606
|
+
# 8. Test run with sample payload ✅ Sprint 3
|
|
607
|
+
# --sync may time out (~30s) even if the run finishes faster.
|
|
608
|
+
# If it times out, use 'workflow runs' + 'run-detail' to fetch the result.
|
|
609
|
+
imbrace workflow run <flowId> --sync \
|
|
610
|
+
--payload '{"text":"How do I reset my password?","channel":"C0XXXXX","ts":"1234.5"}' \
|
|
611
|
+
--json
|
|
612
|
+
|
|
613
|
+
# 9. Publish & enable so it runs automatically ✅ Sprint 3
|
|
614
|
+
imbrace workflow publish <flowId> --json
|
|
615
|
+
imbrace workflow enable <flowId> --json
|
|
616
|
+
```
|
|
617
|
+
|
|
618
|
+
## Adding a New Service
|
|
619
|
+
|
|
620
|
+
To add a new service (e.g. `workflow`):
|
|
621
|
+
|
|
622
|
+
1. Create route in `api/src/routes/workflow.ts`
|
|
623
|
+
2. Mount in `api/src/index.ts` with `authMiddleware`
|
|
624
|
+
3. Create CLI commands in `cli/src/commands/workflow/`
|
|
625
|
+
4. Add topic in `cli/package.json` under `oclif.topics`
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@imbrace/cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "CLI tool for interacting with the Imbrace CRM platform from the terminal",
|
|
6
6
|
"repository": {
|
|
@@ -75,6 +75,7 @@
|
|
|
75
75
|
},
|
|
76
76
|
"files": [
|
|
77
77
|
"/bin",
|
|
78
|
-
"/dist"
|
|
78
|
+
"/dist",
|
|
79
|
+
"/llms.txt"
|
|
79
80
|
]
|
|
80
81
|
}
|