lyzr-cortex-cli 0.1.2

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 ADDED
@@ -0,0 +1,233 @@
1
+ # Lyzr Cortex CLI
2
+
3
+ Command-line tool for Cortex platform developers. Push documents, query the knowledge graph, share with users, and manage tool projects.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ npm install -g lyzr-cortex-cli
9
+ ```
10
+
11
+ ## Configuration
12
+
13
+ Set environment variables (or pass `--api-url`, `--api-key`, `--tool-id` to each command):
14
+
15
+ ```bash
16
+ export CORTEX_API_URL=https://your-cortex-server.com
17
+ export CORTEX_API_KEY=your-api-key
18
+ export CORTEX_TOOL_ID=your-tool-id
19
+ ```
20
+
21
+ ---
22
+
23
+ ## API Commands
24
+
25
+ These commands map directly to the Python (`lyzr-cortex-sdk`) and TypeScript (`lyzr-cortex-sdk`) SDK methods.
26
+
27
+ | CLI Command | Python SDK | TypeScript SDK | HTTP Endpoint |
28
+ |-------------|-----------|---------------|---------------|
29
+ | `cortex push` | `client.push()` | `client.push()` | `POST /api/tools/documents` |
30
+ | `cortex query` | `client.query()` | `client.query()` | `POST /api/tools/query` |
31
+ | `cortex whoami` | `client.get_user_context()` | `client.getUserContext()` | `GET /api/tools/context/{email}` |
32
+ | `cortex share` | `client.share_document()` | `client.shareDocument()` | `POST /api/tools/share-document-for-user` |
33
+ | `cortex users` | `client.get_org_users()` | `client.getOrgUsers()` | `GET /api/tools/org-users-for-tool` |
34
+
35
+ ### `cortex push`
36
+
37
+ Push a document to the Cortex Knowledge Graph.
38
+
39
+ ```bash
40
+ # Push a transcript file
41
+ cortex push transcript_123 --type meeting_transcript --file ./transcript.txt --name "Product Sync"
42
+
43
+ # Push with personal scope
44
+ cortex push doc_456 --type note --file ./note.md --scope personal
45
+
46
+ # Push with team scope
47
+ cortex push doc_789 --type report --file ./report.txt --scope team --teams "team_eng,team_product"
48
+
49
+ # Push with metadata
50
+ cortex push doc_abc --type doc --file ./doc.txt --metadata '{"author":"alice@co.com"}'
51
+ ```
52
+
53
+ Options:
54
+ - `<id>` - Unique document ID (required)
55
+ - `-t, --type <type>` - Document type (required)
56
+ - `-f, --file <path>` - File with document content (required)
57
+ - `-n, --name <name>` - Display name
58
+ - `-u, --url <url>` - External URL
59
+ - `-s, --scope <scope>` - Access scope: `global`, `team`, or `personal` (default: `global`)
60
+ - `--teams <ids>` - Comma-separated team IDs (for team scope)
61
+ - `--metadata <json>` - JSON metadata object
62
+
63
+ ### `cortex query`
64
+
65
+ Query the Cortex Knowledge Graph.
66
+
67
+ ```bash
68
+ # Simple query
69
+ cortex query "What decisions were made about Q1?"
70
+
71
+ # Filter by document type
72
+ cortex query "Latest meeting notes" --filters '{"type":["meeting_transcript"]}'
73
+
74
+ # Limit to recent documents
75
+ cortex query "Action items this week" --time-range 7
76
+
77
+ # Get raw JSON output
78
+ cortex query "Project status" --json
79
+ ```
80
+
81
+ Options:
82
+ - `<question>` - Natural language query (required)
83
+ - `--filters <json>` - JSON filter object
84
+ - `--time-range <days>` - Limit to recent N days
85
+ - `--max-results <n>` - Maximum results (default: 10)
86
+ - `--user-email <email>` - User email for access-scoped queries
87
+ - `--json` - Output raw JSON
88
+
89
+ ### `cortex whoami`
90
+
91
+ Get user context (teams, permissions, org info).
92
+
93
+ ```bash
94
+ cortex whoami alice@company.com
95
+ cortex whoami alice@company.com --json
96
+ ```
97
+
98
+ Options:
99
+ - `<email>` - User email address (required)
100
+ - `--json` - Output raw JSON
101
+
102
+ ### `cortex share`
103
+
104
+ Share a document with another user. The document appears in the recipient's "Shared with Me" at `/personal/shared`.
105
+
106
+ ```bash
107
+ cortex share transcript_123 --from alice@co.com --to bob@co.com --name "Product Sync"
108
+ ```
109
+
110
+ Options:
111
+ - `<document-id>` - External ID of the document (required)
112
+ - `--from <email>` - Sharer's email (required)
113
+ - `--to <email>` - Recipient's email (required)
114
+ - `-n, --name <name>` - Document display name
115
+ - `-c, --content <text>` - Document content
116
+ - `-u, --url <url>` - External URL
117
+ - `--metadata <json>` - JSON metadata object
118
+
119
+ ### `cortex users`
120
+
121
+ List organization users.
122
+
123
+ ```bash
124
+ cortex users
125
+ cortex users --exclude alice@co.com
126
+ cortex users --json
127
+ ```
128
+
129
+ Options:
130
+ - `--exclude <email>` - Exclude an email from results
131
+ - `--json` - Output raw JSON
132
+
133
+ ---
134
+
135
+ ## Project Management Commands
136
+
137
+ ### `cortex init`
138
+
139
+ Initialize a new Cortex tool project.
140
+
141
+ ```bash
142
+ cortex init
143
+ cortex init --name my-tool --description "My awesome tool"
144
+ cortex init -y # Use defaults without prompts
145
+ ```
146
+
147
+ Creates:
148
+ - `cortex.yaml` - Tool manifest
149
+ - `.env.example` - Environment variables template
150
+ - Basic directory structure
151
+
152
+ ### `cortex validate`
153
+
154
+ Validate your `cortex.yaml` manifest.
155
+
156
+ ```bash
157
+ cortex validate
158
+ cortex validate --file path/to/cortex.yaml
159
+ ```
160
+
161
+ ### `cortex dev`
162
+
163
+ Start local development environment.
164
+
165
+ ```bash
166
+ cortex dev
167
+ cortex dev --port 8080
168
+ ```
169
+
170
+ ### `cortex deploy`
171
+
172
+ Deploy your tool to Cortex platform.
173
+
174
+ ```bash
175
+ cortex deploy
176
+ cortex deploy --api-url https://api.cortex.ai --api-key your-key
177
+ cortex deploy --dry-run
178
+ ```
179
+
180
+ ### `cortex status`
181
+
182
+ Check tool registration and health status.
183
+
184
+ ```bash
185
+ cortex status
186
+ cortex status --api-url https://api.cortex.ai --api-key your-key
187
+ ```
188
+
189
+ ---
190
+
191
+ ## Access Scopes
192
+
193
+ | Scope | Who Can See | Cortex UI Location |
194
+ |-------|-------------|-------------------|
195
+ | `global` | Everyone in organization | Organization knowledge base |
196
+ | `team` | Specified team members | Team knowledge base |
197
+ | `personal` | Only the creator | `/personal/transcripts` |
198
+ | Shared via `cortex share` | Recipient | `/personal/shared` |
199
+
200
+ ## Manifest Format (cortex.yaml)
201
+
202
+ ```yaml
203
+ name: my-tool
204
+ display_name: My Tool
205
+ description: A tool that does awesome things
206
+ version: 1.0.0
207
+
208
+ documents:
209
+ - my_document_type
210
+
211
+ icon: puzzle
212
+ ui:
213
+ embed_path: /
214
+ menu:
215
+ label: My Tool
216
+ position: tools
217
+
218
+ build:
219
+ backend:
220
+ dockerfile: backend/Dockerfile
221
+ port: 8000
222
+ health_check: /health
223
+ frontend:
224
+ dockerfile: frontend/Dockerfile
225
+ port: 3000
226
+
227
+ secrets:
228
+ - MY_API_KEY
229
+ ```
230
+
231
+ ## License
232
+
233
+ MIT
@@ -0,0 +1 @@
1
+ #!/usr/bin/env node
package/dist/index.js ADDED
@@ -0,0 +1,753 @@
1
+ #!/usr/bin/env node
2
+ "use strict";
3
+ var __create = Object.create;
4
+ var __defProp = Object.defineProperty;
5
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
6
+ var __getOwnPropNames = Object.getOwnPropertyNames;
7
+ var __getProtoOf = Object.getPrototypeOf;
8
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
9
+ var __copyProps = (to, from, except, desc) => {
10
+ if (from && typeof from === "object" || typeof from === "function") {
11
+ for (let key of __getOwnPropNames(from))
12
+ if (!__hasOwnProp.call(to, key) && key !== except)
13
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
14
+ }
15
+ return to;
16
+ };
17
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
18
+ // If the importer is in node compatibility mode or this is not an ESM
19
+ // file that has been converted to a CommonJS file using a Babel-
20
+ // compatible transform (i.e. "__esModule" has not been set), then set
21
+ // "default" to the CommonJS "module.exports" for node compatibility.
22
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
23
+ mod
24
+ ));
25
+
26
+ // src/index.ts
27
+ var import_commander = require("commander");
28
+ var import_chalk12 = __toESM(require("chalk"));
29
+
30
+ // src/commands/init.ts
31
+ var fs2 = __toESM(require("fs"));
32
+ var path2 = __toESM(require("path"));
33
+ var import_chalk = __toESM(require("chalk"));
34
+ var import_inquirer = __toESM(require("inquirer"));
35
+ var import_ora = __toESM(require("ora"));
36
+
37
+ // src/utils/manifest.ts
38
+ var fs = __toESM(require("fs"));
39
+ var path = __toESM(require("path"));
40
+ var yaml = __toESM(require("js-yaml"));
41
+ function loadManifest(filePath = "cortex.yaml") {
42
+ const fullPath = path.resolve(process.cwd(), filePath);
43
+ if (!fs.existsSync(fullPath)) {
44
+ return null;
45
+ }
46
+ try {
47
+ const content = fs.readFileSync(fullPath, "utf-8");
48
+ const manifest = yaml.load(content);
49
+ return manifest;
50
+ } catch (error) {
51
+ throw new Error(`Failed to parse ${filePath}: ${error}`);
52
+ }
53
+ }
54
+ function validateManifest(manifest) {
55
+ const errors = [];
56
+ if (!manifest.name) {
57
+ errors.push({ field: "name", message: "Tool name is required" });
58
+ } else if (!/^[a-z0-9-]+$/.test(manifest.name)) {
59
+ errors.push({
60
+ field: "name",
61
+ message: "Tool name must be lowercase alphanumeric with hyphens only"
62
+ });
63
+ }
64
+ if (!manifest.display_name) {
65
+ errors.push({ field: "display_name", message: "Display name is required" });
66
+ }
67
+ if (!manifest.version) {
68
+ errors.push({ field: "version", message: "Version is required" });
69
+ } else if (!/^\d+\.\d+\.\d+$/.test(manifest.version)) {
70
+ errors.push({
71
+ field: "version",
72
+ message: "Version must be semver format (e.g., 1.0.0)"
73
+ });
74
+ }
75
+ if (!manifest.documents || !Array.isArray(manifest.documents)) {
76
+ errors.push({
77
+ field: "documents",
78
+ message: "Documents array is required (list of document types this tool produces)"
79
+ });
80
+ }
81
+ if (manifest.build) {
82
+ if (manifest.build.backend) {
83
+ if (manifest.build.backend.port && typeof manifest.build.backend.port !== "number") {
84
+ errors.push({ field: "build.backend.port", message: "Port must be a number" });
85
+ }
86
+ }
87
+ if (manifest.build.frontend) {
88
+ if (manifest.build.frontend.port && typeof manifest.build.frontend.port !== "number") {
89
+ errors.push({ field: "build.frontend.port", message: "Port must be a number" });
90
+ }
91
+ }
92
+ }
93
+ return errors;
94
+ }
95
+ function createDefaultManifest(name, displayName, description) {
96
+ return {
97
+ name,
98
+ display_name: displayName,
99
+ description: description || `${displayName} tool for Cortex platform`,
100
+ version: "1.0.0",
101
+ documents: ["document"],
102
+ icon: "puzzle",
103
+ ui: {
104
+ embed_path: "/",
105
+ menu: {
106
+ label: displayName,
107
+ position: "tools"
108
+ }
109
+ },
110
+ build: {
111
+ backend: {
112
+ dockerfile: "backend/Dockerfile",
113
+ port: 8e3,
114
+ health_check: "/health"
115
+ },
116
+ frontend: {
117
+ dockerfile: "frontend/Dockerfile",
118
+ port: 3e3
119
+ }
120
+ },
121
+ secrets: []
122
+ };
123
+ }
124
+ function writeManifest(manifest, filePath = "cortex.yaml") {
125
+ const fullPath = path.resolve(process.cwd(), filePath);
126
+ const content = yaml.dump(manifest, {
127
+ indent: 2,
128
+ lineWidth: 100,
129
+ noRefs: true
130
+ });
131
+ fs.writeFileSync(fullPath, content, "utf-8");
132
+ }
133
+
134
+ // src/commands/init.ts
135
+ async function initCommand(options) {
136
+ console.log(import_chalk.default.cyan("\n Cortex Tool Initializer\n"));
137
+ if (loadManifest()) {
138
+ console.log(import_chalk.default.yellow(" cortex.yaml already exists in this directory."));
139
+ const { overwrite } = await import_inquirer.default.prompt([
140
+ {
141
+ type: "confirm",
142
+ name: "overwrite",
143
+ message: "Overwrite existing cortex.yaml?",
144
+ default: false
145
+ }
146
+ ]);
147
+ if (!overwrite) {
148
+ console.log(import_chalk.default.gray(" Initialization cancelled."));
149
+ return;
150
+ }
151
+ }
152
+ let name;
153
+ let displayName;
154
+ let description;
155
+ let documentTypes;
156
+ if (options.yes) {
157
+ const dirName = path2.basename(process.cwd());
158
+ name = options.name || dirName.toLowerCase().replace(/[^a-z0-9-]/g, "-");
159
+ displayName = name.split("-").map((w) => w.charAt(0).toUpperCase() + w.slice(1)).join(" ");
160
+ description = options.description || `${displayName} tool for Cortex`;
161
+ documentTypes = ["document"];
162
+ } else {
163
+ const answers = await import_inquirer.default.prompt([
164
+ {
165
+ type: "input",
166
+ name: "name",
167
+ message: "Tool name (lowercase, hyphens only):",
168
+ default: options.name || path2.basename(process.cwd()).toLowerCase().replace(/[^a-z0-9-]/g, "-"),
169
+ validate: (input) => /^[a-z0-9-]+$/.test(input) || "Name must be lowercase alphanumeric with hyphens"
170
+ },
171
+ {
172
+ type: "input",
173
+ name: "displayName",
174
+ message: "Display name:",
175
+ default: (answers2) => answers2.name.split("-").map((w) => w.charAt(0).toUpperCase() + w.slice(1)).join(" ")
176
+ },
177
+ {
178
+ type: "input",
179
+ name: "description",
180
+ message: "Description:",
181
+ default: options.description
182
+ },
183
+ {
184
+ type: "input",
185
+ name: "documentTypes",
186
+ message: "Document types (comma-separated):",
187
+ default: "document"
188
+ }
189
+ ]);
190
+ name = answers.name;
191
+ displayName = answers.displayName;
192
+ description = answers.description;
193
+ documentTypes = answers.documentTypes.split(",").map((t) => t.trim());
194
+ }
195
+ const spinner = (0, import_ora.default)("Creating cortex.yaml...").start();
196
+ try {
197
+ const manifest = createDefaultManifest(name, displayName, description);
198
+ manifest.documents = documentTypes;
199
+ writeManifest(manifest);
200
+ spinner.succeed("Created cortex.yaml");
201
+ const dirs = ["backend", "frontend"];
202
+ for (const dir of dirs) {
203
+ if (!fs2.existsSync(dir)) {
204
+ fs2.mkdirSync(dir, { recursive: true });
205
+ console.log(import_chalk.default.gray(` Created ${dir}/`));
206
+ }
207
+ }
208
+ const envExample = `# Cortex Integration
209
+ CORTEX_ENABLED=false
210
+ CORTEX_API_URL=
211
+ CORTEX_API_KEY=
212
+ CORTEX_TOOL_ID=${name}
213
+ CORTEX_JWT_PUBLIC_KEY=
214
+ `;
215
+ if (!fs2.existsSync(".env.example")) {
216
+ fs2.writeFileSync(".env.example", envExample, "utf-8");
217
+ console.log(import_chalk.default.gray(" Created .env.example"));
218
+ }
219
+ console.log(import_chalk.default.green("\n Tool initialized successfully!\n"));
220
+ console.log(import_chalk.default.gray(" Next steps:"));
221
+ console.log(import_chalk.default.gray(" 1. Edit cortex.yaml with your tool configuration"));
222
+ console.log(import_chalk.default.gray(" 2. Implement your backend and frontend"));
223
+ console.log(import_chalk.default.gray(" 3. Run `cortex validate` to check your manifest"));
224
+ console.log(import_chalk.default.gray(" 4. Run `cortex dev` to start local development\n"));
225
+ } catch (error) {
226
+ spinner.fail("Failed to create cortex.yaml");
227
+ console.error(import_chalk.default.red(` Error: ${error}`));
228
+ process.exit(1);
229
+ }
230
+ }
231
+
232
+ // src/commands/validate.ts
233
+ var import_chalk2 = __toESM(require("chalk"));
234
+ async function validateCommand(options) {
235
+ const filePath = options.file || "cortex.yaml";
236
+ console.log(import_chalk2.default.cyan(`
237
+ Validating ${filePath}...
238
+ `));
239
+ const manifest = loadManifest(filePath);
240
+ if (!manifest) {
241
+ console.log(import_chalk2.default.red(` Error: ${filePath} not found.`));
242
+ console.log(import_chalk2.default.gray(" Run `cortex init` to create a manifest.\n"));
243
+ process.exit(1);
244
+ }
245
+ const errors = validateManifest(manifest);
246
+ if (errors.length === 0) {
247
+ console.log(import_chalk2.default.green(" \u2713 Manifest is valid!\n"));
248
+ console.log(import_chalk2.default.gray(" Summary:"));
249
+ console.log(import_chalk2.default.gray(` Name: ${manifest.name}`));
250
+ console.log(import_chalk2.default.gray(` Display Name: ${manifest.display_name}`));
251
+ console.log(import_chalk2.default.gray(` Version: ${manifest.version}`));
252
+ console.log(import_chalk2.default.gray(` Documents: ${manifest.documents.join(", ")}`));
253
+ if (manifest.build?.backend) {
254
+ console.log(import_chalk2.default.gray(` Backend Port: ${manifest.build.backend.port}`));
255
+ }
256
+ if (manifest.build?.frontend) {
257
+ console.log(import_chalk2.default.gray(` Frontend Port: ${manifest.build.frontend.port}`));
258
+ }
259
+ console.log("");
260
+ process.exit(0);
261
+ } else {
262
+ console.log(import_chalk2.default.red(` \u2717 Found ${errors.length} error(s):
263
+ `));
264
+ for (const error of errors) {
265
+ console.log(import_chalk2.default.red(` \u2022 ${error.field}: ${error.message}`));
266
+ }
267
+ console.log("");
268
+ process.exit(1);
269
+ }
270
+ }
271
+
272
+ // src/commands/dev.ts
273
+ var import_chalk3 = __toESM(require("chalk"));
274
+ var import_ora2 = __toESM(require("ora"));
275
+ async function devCommand(options) {
276
+ console.log(import_chalk3.default.cyan("\n Cortex Development Server\n"));
277
+ const manifest = loadManifest();
278
+ if (!manifest) {
279
+ console.log(import_chalk3.default.red(" Error: cortex.yaml not found."));
280
+ console.log(import_chalk3.default.gray(" Run `cortex init` first.\n"));
281
+ process.exit(1);
282
+ }
283
+ const errors = validateManifest(manifest);
284
+ if (errors.length > 0) {
285
+ console.log(import_chalk3.default.red(" Error: Invalid manifest. Run `cortex validate` for details.\n"));
286
+ process.exit(1);
287
+ }
288
+ const port = options.port || String(manifest.build?.backend?.port || 8e3);
289
+ console.log(import_chalk3.default.gray(` Tool: ${manifest.display_name}`));
290
+ console.log(import_chalk3.default.gray(` Version: ${manifest.version}`));
291
+ console.log("");
292
+ const spinner = (0, import_ora2.default)("Starting development environment...").start();
293
+ setTimeout(() => {
294
+ spinner.succeed("Development environment ready");
295
+ console.log(import_chalk3.default.green("\n Local development server started!\n"));
296
+ console.log(import_chalk3.default.gray(" Environment variables set:"));
297
+ console.log(import_chalk3.default.gray(` CORTEX_ENABLED=true`));
298
+ console.log(import_chalk3.default.gray(` CORTEX_API_URL=http://localhost:${port}/api/tools`));
299
+ console.log(import_chalk3.default.gray(` CORTEX_API_KEY=dev-key-${manifest.name}`));
300
+ console.log(import_chalk3.default.gray(` CORTEX_TOOL_ID=${manifest.name}`));
301
+ console.log("");
302
+ console.log(import_chalk3.default.gray(" To start your tool:"));
303
+ console.log(import_chalk3.default.gray(" 1. Set the environment variables above in your .env"));
304
+ console.log(import_chalk3.default.gray(" 2. Start your backend and frontend services"));
305
+ console.log(import_chalk3.default.gray(" 3. Your tool will connect to the local Cortex gateway"));
306
+ console.log("");
307
+ console.log(import_chalk3.default.cyan(" Press Ctrl+C to stop\n"));
308
+ }, 1e3);
309
+ }
310
+
311
+ // src/commands/deploy.ts
312
+ var import_chalk4 = __toESM(require("chalk"));
313
+ var import_ora3 = __toESM(require("ora"));
314
+ var import_inquirer2 = __toESM(require("inquirer"));
315
+ async function deployCommand(options) {
316
+ console.log(import_chalk4.default.cyan("\n Cortex Tool Deployment\n"));
317
+ const manifest = loadManifest();
318
+ if (!manifest) {
319
+ console.log(import_chalk4.default.red(" Error: cortex.yaml not found."));
320
+ console.log(import_chalk4.default.gray(" Run `cortex init` first.\n"));
321
+ process.exit(1);
322
+ }
323
+ const errors = validateManifest(manifest);
324
+ if (errors.length > 0) {
325
+ console.log(import_chalk4.default.red(" Error: Invalid manifest. Run `cortex validate` for details.\n"));
326
+ process.exit(1);
327
+ }
328
+ let apiUrl = options.apiUrl || process.env.CORTEX_API_URL;
329
+ let apiKey = options.apiKey || process.env.CORTEX_API_KEY;
330
+ if (!apiUrl || !apiKey) {
331
+ console.log(import_chalk4.default.yellow(" Cortex API credentials not provided.\n"));
332
+ const answers = await import_inquirer2.default.prompt([
333
+ {
334
+ type: "input",
335
+ name: "apiUrl",
336
+ message: "Cortex API URL:",
337
+ default: apiUrl || "https://api.cortex.ai",
338
+ when: !apiUrl
339
+ },
340
+ {
341
+ type: "password",
342
+ name: "apiKey",
343
+ message: "Cortex API Key:",
344
+ when: !apiKey
345
+ }
346
+ ]);
347
+ apiUrl = apiUrl || answers.apiUrl;
348
+ apiKey = apiKey || answers.apiKey;
349
+ }
350
+ if (!apiUrl || !apiKey) {
351
+ console.log(import_chalk4.default.red(" Error: API URL and API Key are required.\n"));
352
+ process.exit(1);
353
+ }
354
+ console.log(import_chalk4.default.gray(` Tool: ${manifest.display_name} (${manifest.name})`));
355
+ console.log(import_chalk4.default.gray(` Version: ${manifest.version}`));
356
+ console.log(import_chalk4.default.gray(` Documents: ${manifest.documents.join(", ")}`));
357
+ console.log(import_chalk4.default.gray(` Target: ${apiUrl}`));
358
+ console.log("");
359
+ if (options.dryRun) {
360
+ console.log(import_chalk4.default.yellow(" Dry run mode - no changes will be made.\n"));
361
+ console.log(import_chalk4.default.gray(" Would deploy:"));
362
+ console.log(import_chalk4.default.gray(` \u2022 Register tool: ${manifest.name}`));
363
+ console.log(import_chalk4.default.gray(` \u2022 Document types: ${manifest.documents.join(", ")}`));
364
+ if (manifest.build?.backend) {
365
+ console.log(import_chalk4.default.gray(` \u2022 Backend: ${manifest.build.backend.dockerfile}`));
366
+ }
367
+ if (manifest.build?.frontend) {
368
+ console.log(import_chalk4.default.gray(` \u2022 Frontend: ${manifest.build.frontend.dockerfile}`));
369
+ }
370
+ console.log("");
371
+ return;
372
+ }
373
+ const { confirm } = await import_inquirer2.default.prompt([
374
+ {
375
+ type: "confirm",
376
+ name: "confirm",
377
+ message: "Deploy to Cortex platform?",
378
+ default: true
379
+ }
380
+ ]);
381
+ if (!confirm) {
382
+ console.log(import_chalk4.default.gray(" Deployment cancelled.\n"));
383
+ return;
384
+ }
385
+ const spinner = (0, import_ora3.default)("Deploying to Cortex...").start();
386
+ try {
387
+ await new Promise((resolve2) => setTimeout(resolve2, 2e3));
388
+ spinner.succeed("Deployment complete!");
389
+ console.log(import_chalk4.default.green("\n Tool deployed successfully!\n"));
390
+ console.log(import_chalk4.default.gray(" Your tool is now available in Cortex."));
391
+ console.log(import_chalk4.default.gray(` Tool URL: ${apiUrl}/tools/${manifest.name}`));
392
+ console.log("");
393
+ } catch (error) {
394
+ spinner.fail("Deployment failed");
395
+ console.error(import_chalk4.default.red(` Error: ${error}`));
396
+ process.exit(1);
397
+ }
398
+ }
399
+
400
+ // src/commands/status.ts
401
+ var import_chalk5 = __toESM(require("chalk"));
402
+ var import_ora4 = __toESM(require("ora"));
403
+ async function statusCommand(options) {
404
+ console.log(import_chalk5.default.cyan("\n Cortex Tool Status\n"));
405
+ const manifest = loadManifest();
406
+ if (!manifest) {
407
+ console.log(import_chalk5.default.yellow(" No cortex.yaml found - showing general status.\n"));
408
+ } else {
409
+ console.log(import_chalk5.default.gray(` Tool: ${manifest.display_name} (${manifest.name})`));
410
+ console.log(import_chalk5.default.gray(` Version: ${manifest.version}`));
411
+ console.log("");
412
+ }
413
+ const apiUrl = options.apiUrl || process.env.CORTEX_API_URL;
414
+ const apiKey = options.apiKey || process.env.CORTEX_API_KEY;
415
+ if (!apiUrl || !apiKey) {
416
+ console.log(import_chalk5.default.gray(" Local Status:"));
417
+ console.log(import_chalk5.default.gray(" cortex.yaml: " + (manifest ? import_chalk5.default.green("\u2713 Found") : import_chalk5.default.red("\u2717 Not found"))));
418
+ if (manifest) {
419
+ const hasBackend = manifest.build?.backend?.dockerfile && require("fs").existsSync(manifest.build.backend.dockerfile.split("/")[0]);
420
+ const hasFrontend = manifest.build?.frontend?.dockerfile && require("fs").existsSync(manifest.build.frontend.dockerfile.split("/")[0]);
421
+ console.log(
422
+ import_chalk5.default.gray(" Backend: " + (hasBackend ? import_chalk5.default.green("\u2713 Found") : import_chalk5.default.yellow("\u25CB Not found")))
423
+ );
424
+ console.log(
425
+ import_chalk5.default.gray(" Frontend: " + (hasFrontend ? import_chalk5.default.green("\u2713 Found") : import_chalk5.default.yellow("\u25CB Not found")))
426
+ );
427
+ }
428
+ console.log("");
429
+ console.log(import_chalk5.default.gray(" To check remote status, provide --api-url and --api-key"));
430
+ console.log(import_chalk5.default.gray(" or set CORTEX_API_URL and CORTEX_API_KEY environment variables.\n"));
431
+ return;
432
+ }
433
+ const spinner = (0, import_ora4.default)("Checking status...").start();
434
+ try {
435
+ await new Promise((resolve2) => setTimeout(resolve2, 1e3));
436
+ spinner.stop();
437
+ console.log(import_chalk5.default.gray(" Remote Status:"));
438
+ console.log(import_chalk5.default.gray(` API: ${apiUrl}`));
439
+ if (manifest) {
440
+ console.log(import_chalk5.default.gray(` Registration: ${import_chalk5.default.green("\u2713 Registered")}`));
441
+ console.log(import_chalk5.default.gray(` Status: ${import_chalk5.default.green("Active")}`));
442
+ console.log(import_chalk5.default.gray(` Last Deployed: 2024-01-15 10:30:00`));
443
+ console.log(import_chalk5.default.gray(` Documents Pushed: 1,234`));
444
+ console.log(import_chalk5.default.gray(` Queries Served: 5,678`));
445
+ } else {
446
+ console.log(import_chalk5.default.gray(` Connection: ${import_chalk5.default.green("\u2713 Connected")}`));
447
+ }
448
+ console.log("");
449
+ } catch (error) {
450
+ spinner.fail("Failed to check status");
451
+ console.error(import_chalk5.default.red(` Error: ${error}`));
452
+ console.log("");
453
+ process.exit(1);
454
+ }
455
+ }
456
+
457
+ // src/commands/push.ts
458
+ var import_chalk7 = __toESM(require("chalk"));
459
+ var import_ora5 = __toESM(require("ora"));
460
+ var fs3 = __toESM(require("fs"));
461
+
462
+ // src/utils/api.ts
463
+ var import_chalk6 = __toESM(require("chalk"));
464
+ function resolveConfig(options) {
465
+ const apiUrl = options.apiUrl || process.env.CORTEX_API_URL;
466
+ const apiKey = options.apiKey || process.env.CORTEX_API_KEY;
467
+ const toolId = options.toolId || process.env.CORTEX_TOOL_ID || "";
468
+ if (!apiUrl || !apiKey) {
469
+ console.log(import_chalk6.default.red("\n Error: Missing API credentials.\n"));
470
+ console.log(import_chalk6.default.gray(" Provide --api-url and --api-key options, or set environment variables:"));
471
+ console.log(import_chalk6.default.gray(" CORTEX_API_URL=https://your-cortex-server.com"));
472
+ console.log(import_chalk6.default.gray(" CORTEX_API_KEY=your-api-key"));
473
+ console.log(import_chalk6.default.gray(" CORTEX_TOOL_ID=your-tool-id\n"));
474
+ return null;
475
+ }
476
+ return { apiUrl: apiUrl.replace(/\/$/, ""), apiKey, toolId };
477
+ }
478
+ async function apiRequest(config, method, path3, body) {
479
+ const url = `${config.apiUrl}${path3}`;
480
+ const headers = {
481
+ "Content-Type": "application/json",
482
+ "X-API-Key": config.apiKey
483
+ };
484
+ if (config.toolId) {
485
+ headers["X-Cortex-Tool-ID"] = config.toolId;
486
+ }
487
+ const response = await fetch(url, {
488
+ method,
489
+ headers,
490
+ body: body ? JSON.stringify(body) : void 0
491
+ });
492
+ if (!response.ok) {
493
+ const errorText = await response.text();
494
+ throw new Error(`API error (${response.status}): ${errorText}`);
495
+ }
496
+ const text = await response.text();
497
+ return text ? JSON.parse(text) : {};
498
+ }
499
+
500
+ // src/commands/push.ts
501
+ async function pushCommand(id, options) {
502
+ const config = resolveConfig(options);
503
+ if (!config) process.exit(1);
504
+ let content;
505
+ if (options.file) {
506
+ if (!fs3.existsSync(options.file)) {
507
+ console.log(import_chalk7.default.red(`
508
+ Error: File not found: ${options.file}
509
+ `));
510
+ process.exit(1);
511
+ }
512
+ content = fs3.readFileSync(options.file, "utf-8");
513
+ } else {
514
+ console.log(import_chalk7.default.red("\n Error: --file <path> is required to provide document content.\n"));
515
+ process.exit(1);
516
+ }
517
+ let metadata;
518
+ if (options.metadata) {
519
+ try {
520
+ metadata = JSON.parse(options.metadata);
521
+ } catch {
522
+ console.log(import_chalk7.default.red("\n Error: --metadata must be valid JSON.\n"));
523
+ process.exit(1);
524
+ }
525
+ }
526
+ const teamIds = options.teams ? options.teams.split(",").map((t) => t.trim()) : void 0;
527
+ const spinner = (0, import_ora5.default)("Pushing document to Cortex...").start();
528
+ try {
529
+ const result = await apiRequest(
530
+ config,
531
+ "POST",
532
+ "/api/tools/documents",
533
+ {
534
+ external_id: id,
535
+ document_type: options.type,
536
+ content,
537
+ name: options.name || id,
538
+ external_url: options.url,
539
+ access_scope: options.scope || "global",
540
+ scope_team_ids: teamIds,
541
+ metadata
542
+ }
543
+ );
544
+ spinner.succeed("Document pushed successfully");
545
+ console.log(import_chalk7.default.gray(`
546
+ ID: ${result.id || id}`));
547
+ console.log(import_chalk7.default.gray(` Status: ${result.status || "ok"}`));
548
+ console.log(import_chalk7.default.gray(` Type: ${options.type}`));
549
+ console.log(import_chalk7.default.gray(` Scope: ${options.scope || "global"}
550
+ `));
551
+ } catch (error) {
552
+ spinner.fail("Failed to push document");
553
+ console.error(import_chalk7.default.red(` ${error}
554
+ `));
555
+ process.exit(1);
556
+ }
557
+ }
558
+
559
+ // src/commands/query.ts
560
+ var import_chalk8 = __toESM(require("chalk"));
561
+ var import_ora6 = __toESM(require("ora"));
562
+ async function queryCommand(question, options) {
563
+ const config = resolveConfig(options);
564
+ if (!config) process.exit(1);
565
+ let filters;
566
+ if (options.filters) {
567
+ try {
568
+ filters = JSON.parse(options.filters);
569
+ } catch {
570
+ console.log(import_chalk8.default.red("\n Error: --filters must be valid JSON.\n"));
571
+ process.exit(1);
572
+ }
573
+ }
574
+ const spinner = (0, import_ora6.default)("Querying Cortex...").start();
575
+ try {
576
+ const result = await apiRequest(config, "POST", "/api/tools/query", {
577
+ query: question,
578
+ filters,
579
+ time_range_days: options.timeRange ? parseInt(options.timeRange, 10) : void 0,
580
+ max_results: options.maxResults ? parseInt(options.maxResults, 10) : 10,
581
+ user_email: options.userEmail
582
+ });
583
+ spinner.stop();
584
+ if (options.json) {
585
+ console.log(JSON.stringify(result, null, 2));
586
+ return;
587
+ }
588
+ console.log(import_chalk8.default.cyan("\n Answer:\n"));
589
+ console.log(` ${result.answer}
590
+ `);
591
+ if (result.sources && result.sources.length > 0) {
592
+ console.log(import_chalk8.default.gray(` Sources (${result.sources.length}):`));
593
+ for (const source of result.sources) {
594
+ console.log(import_chalk8.default.gray(` \u2022 [${source.type}] ${source.name}`));
595
+ if (source.excerpt) {
596
+ console.log(import_chalk8.default.gray(` ${source.excerpt.substring(0, 120)}...`));
597
+ }
598
+ }
599
+ }
600
+ console.log("");
601
+ } catch (error) {
602
+ spinner.fail("Query failed");
603
+ console.error(import_chalk8.default.red(` ${error}
604
+ `));
605
+ process.exit(1);
606
+ }
607
+ }
608
+
609
+ // src/commands/whoami.ts
610
+ var import_chalk9 = __toESM(require("chalk"));
611
+ var import_ora7 = __toESM(require("ora"));
612
+ async function whoamiCommand(email, options) {
613
+ const config = resolveConfig(options);
614
+ if (!config) process.exit(1);
615
+ const spinner = (0, import_ora7.default)(`Looking up ${email}...`).start();
616
+ try {
617
+ const user = await apiRequest(config, "GET", `/api/tools/context/${encodeURIComponent(email)}`);
618
+ spinner.stop();
619
+ if (options.json) {
620
+ console.log(JSON.stringify(user, null, 2));
621
+ return;
622
+ }
623
+ console.log(import_chalk9.default.cyan("\n User Context:\n"));
624
+ console.log(import_chalk9.default.gray(` Email: ${user.email}`));
625
+ if (user.full_name) console.log(import_chalk9.default.gray(` Name: ${user.full_name}`));
626
+ if (user.org_name) console.log(import_chalk9.default.gray(` Org: ${user.org_name}`));
627
+ if (user.role) console.log(import_chalk9.default.gray(` Role: ${user.role}`));
628
+ if (user.teams && user.teams.length > 0) {
629
+ console.log(import_chalk9.default.gray(` Teams:`));
630
+ for (const team of user.teams) {
631
+ console.log(import_chalk9.default.gray(` \u2022 ${team.name} (${team.id})`));
632
+ }
633
+ }
634
+ if (user.permissions && user.permissions.length > 0) {
635
+ console.log(import_chalk9.default.gray(` Permissions: ${user.permissions.join(", ")}`));
636
+ }
637
+ console.log("");
638
+ } catch (error) {
639
+ spinner.fail("Failed to get user context");
640
+ if (String(error).includes("404")) {
641
+ console.log(import_chalk9.default.yellow(` User ${email} not found in Cortex.
642
+ `));
643
+ } else {
644
+ console.error(import_chalk9.default.red(` ${error}
645
+ `));
646
+ }
647
+ process.exit(1);
648
+ }
649
+ }
650
+
651
+ // src/commands/share.ts
652
+ var import_chalk10 = __toESM(require("chalk"));
653
+ var import_ora8 = __toESM(require("ora"));
654
+ async function shareCommand(documentId, options) {
655
+ const config = resolveConfig(options);
656
+ if (!config) process.exit(1);
657
+ if (!options.from || !options.to) {
658
+ console.log(import_chalk10.default.red("\n Error: --from and --to email addresses are required.\n"));
659
+ console.log(import_chalk10.default.gray(" Usage: cortex share <document-id> --from alice@co.com --to bob@co.com\n"));
660
+ process.exit(1);
661
+ }
662
+ let metadata;
663
+ if (options.metadata) {
664
+ try {
665
+ metadata = JSON.parse(options.metadata);
666
+ } catch {
667
+ console.log(import_chalk10.default.red("\n Error: --metadata must be valid JSON.\n"));
668
+ process.exit(1);
669
+ }
670
+ }
671
+ const spinner = (0, import_ora8.default)(`Sharing document with ${options.to}...`).start();
672
+ try {
673
+ const result = await apiRequest(
674
+ config,
675
+ "POST",
676
+ "/api/tools/share-document-for-user",
677
+ {
678
+ document_external_id: documentId,
679
+ shared_by_email: options.from,
680
+ shared_with_email: options.to,
681
+ document_name: options.name,
682
+ content: options.content,
683
+ external_url: options.url,
684
+ metadata
685
+ }
686
+ );
687
+ spinner.succeed("Document shared successfully");
688
+ console.log(import_chalk10.default.gray(`
689
+ Document: ${documentId}`));
690
+ console.log(import_chalk10.default.gray(` From: ${options.from}`));
691
+ console.log(import_chalk10.default.gray(` To: ${options.to}`));
692
+ if (result.id) console.log(import_chalk10.default.gray(` Share ID: ${result.id}`));
693
+ console.log("");
694
+ } catch (error) {
695
+ spinner.fail("Failed to share document");
696
+ console.error(import_chalk10.default.red(` ${error}
697
+ `));
698
+ process.exit(1);
699
+ }
700
+ }
701
+
702
+ // src/commands/users.ts
703
+ var import_chalk11 = __toESM(require("chalk"));
704
+ var import_ora9 = __toESM(require("ora"));
705
+ async function usersCommand(options) {
706
+ const config = resolveConfig(options);
707
+ if (!config) process.exit(1);
708
+ const spinner = (0, import_ora9.default)("Fetching organization users...").start();
709
+ try {
710
+ const params = options.exclude ? `?exclude_email=${encodeURIComponent(options.exclude)}` : "";
711
+ const users = await apiRequest(config, "GET", `/api/tools/org-users-for-tool${params}`);
712
+ spinner.stop();
713
+ if (options.json) {
714
+ console.log(JSON.stringify(users, null, 2));
715
+ return;
716
+ }
717
+ console.log(import_chalk11.default.cyan(`
718
+ Organization Users (${users.length}):
719
+ `));
720
+ if (users.length === 0) {
721
+ console.log(import_chalk11.default.gray(" No users found.\n"));
722
+ return;
723
+ }
724
+ for (const user of users) {
725
+ console.log(import_chalk11.default.gray(` \u2022 ${user.full_name || "Unknown"} <${user.email}>`));
726
+ }
727
+ console.log("");
728
+ } catch (error) {
729
+ spinner.fail("Failed to fetch users");
730
+ console.error(import_chalk11.default.red(` ${error}
731
+ `));
732
+ process.exit(1);
733
+ }
734
+ }
735
+
736
+ // src/index.ts
737
+ var program = new import_commander.Command();
738
+ program.name("cortex").description("CLI tool for Cortex platform developers").version("0.1.2");
739
+ program.command("init").description("Initialize a new Cortex tool project").option("-n, --name <name>", "Tool name").option("-d, --description <desc>", "Tool description").option("-y, --yes", "Skip prompts and use defaults").action(initCommand);
740
+ program.command("validate").description("Validate cortex.yaml manifest").option("-f, --file <path>", "Path to manifest file", "cortex.yaml").action(validateCommand);
741
+ program.command("dev").description("Start local development environment").option("-p, --port <port>", "API port", "8000").option("--no-browser", "Do not open browser").action(devCommand);
742
+ program.command("deploy").description("Deploy tool to Cortex platform").option("--api-url <url>", "Cortex API URL").option("--api-key <key>", "Cortex API key").option("--dry-run", "Show what would be deployed without deploying").action(deployCommand);
743
+ program.command("status").description("Check tool registration status").option("--api-url <url>", "Cortex API URL").option("--api-key <key>", "Cortex API key").action(statusCommand);
744
+ program.command("push <id>").description("Push a document to Cortex Knowledge Graph").requiredOption("-t, --type <type>", "Document type (e.g., meeting_transcript)").requiredOption("-f, --file <path>", "File containing document content").option("-n, --name <name>", "Display name for the document").option("-u, --url <url>", "External URL for the document").option("-s, --scope <scope>", "Access scope: global, team, or personal", "global").option("--teams <ids>", "Comma-separated team IDs (for team scope)").option("--metadata <json>", "JSON metadata object").option("--api-url <url>", "Cortex API URL").option("--api-key <key>", "Cortex API key").option("--tool-id <id>", "Cortex Tool ID").action(pushCommand);
745
+ program.command("query <question>").description("Query the Cortex Knowledge Graph").option("--filters <json>", `JSON filter object (e.g., '{"type":["meeting_transcript"]}')`).option("--time-range <days>", "Limit to recent N days").option("--max-results <n>", "Maximum results", "10").option("--user-email <email>", "User email for access-scoped queries").option("--json", "Output raw JSON").option("--api-url <url>", "Cortex API URL").option("--api-key <key>", "Cortex API key").option("--tool-id <id>", "Cortex Tool ID").action(queryCommand);
746
+ program.command("whoami <email>").description("Get user context from Cortex").option("--json", "Output raw JSON").option("--api-url <url>", "Cortex API URL").option("--api-key <key>", "Cortex API key").option("--tool-id <id>", "Cortex Tool ID").action(whoamiCommand);
747
+ program.command("share <document-id>").description("Share a document with another user").requiredOption("--from <email>", "Sharer email address").requiredOption("--to <email>", "Recipient email address").option("-n, --name <name>", "Document display name").option("-c, --content <text>", "Document content").option("-u, --url <url>", "External URL").option("--metadata <json>", "JSON metadata object").option("--api-url <url>", "Cortex API URL").option("--api-key <key>", "Cortex API key").option("--tool-id <id>", "Cortex Tool ID").action(shareCommand);
748
+ program.command("users").description("List organization users").option("--exclude <email>", "Exclude email from results").option("--json", "Output raw JSON").option("--api-url <url>", "Cortex API URL").option("--api-key <key>", "Cortex API key").option("--tool-id <id>", "Cortex Tool ID").action(usersCommand);
749
+ program.parse();
750
+ if (!process.argv.slice(2).length) {
751
+ console.log(import_chalk12.default.cyan("\n Cortex CLI - Build tools for Cortex platform\n"));
752
+ program.help();
753
+ }
package/package.json ADDED
@@ -0,0 +1,55 @@
1
+ {
2
+ "name": "lyzr-cortex-cli",
3
+ "version": "0.1.2",
4
+ "description": "CLI tool for Cortex platform developers - push, query, share documents and manage tools",
5
+ "author": "Cortex Lyzr AI",
6
+ "email": "krish@lyzr.ai",
7
+ "license": "MIT",
8
+ "bin": {
9
+ "cortex": "./dist/index.js"
10
+ },
11
+ "main": "dist/index.js",
12
+ "types": "dist/index.d.ts",
13
+ "files": [
14
+ "dist"
15
+ ],
16
+ "scripts": {
17
+ "build": "tsup src/index.ts --format cjs --dts --clean",
18
+ "dev": "tsup src/index.ts --format cjs --dts --watch",
19
+ "start": "node dist/index.js",
20
+ "typecheck": "tsc --noEmit",
21
+ "prepublishOnly": "npm run build"
22
+ },
23
+ "dependencies": {
24
+ "chalk": "^4.1.2",
25
+ "commander": "^11.1.0",
26
+ "inquirer": "^8.2.6",
27
+ "js-yaml": "^4.1.0",
28
+ "ora": "^5.4.1"
29
+ },
30
+ "devDependencies": {
31
+ "@types/inquirer": "^9.0.7",
32
+ "@types/js-yaml": "^4.0.9",
33
+ "@types/node": "^20.10.0",
34
+ "tsup": "^8.0.0",
35
+ "typescript": "^5.3.0"
36
+ },
37
+ "engines": {
38
+ "node": ">=16.0.0"
39
+ },
40
+ "keywords": [
41
+ "cortex",
42
+ "cli",
43
+ "tools",
44
+ "sdk",
45
+ "knowledge-graph",
46
+ "rag",
47
+ "lyzr"
48
+ ],
49
+ "homepage": "https://cortex.lyzr.app/docs",
50
+ "repository": {
51
+ "type": "git"
52
+ },
53
+ "bugs": {
54
+ }
55
+ }