@crewx/cli 0.8.2-rc.2 → 0.8.2-rc.4
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,33 @@
|
|
|
1
|
+
# CrewX CLI
|
|
2
|
+
|
|
3
|
+
> Build AI agent teams from your terminal.
|
|
4
|
+
|
|
5
|
+
[](https://www.npmjs.com/package/@crewx/cli)
|
|
6
|
+
[](LICENSE)
|
|
7
|
+
|
|
8
|
+
## Installation
|
|
9
|
+
|
|
10
|
+
```bash
|
|
11
|
+
npm install -g @crewx/cli
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
## Quick Start
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
crewx q "@assistant hello"
|
|
18
|
+
crewx x "@coder implement feature X"
|
|
19
|
+
crewx agent list
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
Run `crewx --help` for the full list.
|
|
23
|
+
|
|
24
|
+
## What is CrewX?
|
|
25
|
+
|
|
26
|
+
CrewX lets you define AI agents in a single `crewx.yaml` and call them from the terminal.
|
|
27
|
+
|
|
28
|
+
This repository contains the **CrewX CLI** — a thin wrapper over the [`@crewx/sdk`](https://www.npmjs.com/package/@crewx/sdk) runtime (distributed via npm).
|
|
29
|
+
|
|
30
|
+
## License
|
|
31
|
+
|
|
32
|
+
CLI source: [Apache-2.0](LICENSE).
|
|
33
|
+
`@crewx/sdk` runtime: proprietary on npm.
|
package/dist/main.js
CHANGED
|
@@ -58,6 +58,7 @@ const result_1 = require("./commands/result");
|
|
|
58
58
|
const log_1 = require("./commands/log");
|
|
59
59
|
const doctor_1 = require("./commands/doctor");
|
|
60
60
|
const init_1 = require("./commands/init");
|
|
61
|
+
const workspace_repository_1 = require("./repository/workspace.repository");
|
|
61
62
|
const builtin_1 = require("./builtin");
|
|
62
63
|
const slack_1 = require("./commands/slack");
|
|
63
64
|
const install_1 = require("./commands/hook/install");
|
|
@@ -145,6 +146,7 @@ async function main() {
|
|
|
145
146
|
const force = initArgs.includes('--force') || initArgs.includes('-f');
|
|
146
147
|
try {
|
|
147
148
|
const r = await (0, init_1.handleInit)({ path: process.cwd(), force });
|
|
149
|
+
new workspace_repository_1.WorkspaceRepository().registerWorkspace(process.cwd());
|
|
148
150
|
if (r.skippedReason === 'yaml-exists') {
|
|
149
151
|
console.log('✓ crewx.yaml already exists (use --force to overwrite)');
|
|
150
152
|
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import BetterSqlite3 from 'better-sqlite3';
|
|
2
|
+
export interface WorkspaceRepositoryOptions {
|
|
3
|
+
/** Root directory under which `.crewx/crewx.db` lives. Defaults to `os.homedir()`. */
|
|
4
|
+
dbRoot?: string;
|
|
5
|
+
}
|
|
6
|
+
export declare class WorkspaceRepository {
|
|
7
|
+
private readonly dbPath;
|
|
8
|
+
constructor(opts?: WorkspaceRepositoryOptions);
|
|
9
|
+
/**
|
|
10
|
+
* Register a CLI workspace in the global CrewX DB.
|
|
11
|
+
*
|
|
12
|
+
* This is intentionally CLI-owned, not SDK-owned: workspace registration is
|
|
13
|
+
* CrewX application metadata, while the SDK only needs pure workspace helpers.
|
|
14
|
+
* Registration is best-effort so `crewx init` remains usable even if tracing
|
|
15
|
+
* DB setup fails.
|
|
16
|
+
*/
|
|
17
|
+
registerWorkspace(workspacePath: string): void;
|
|
18
|
+
ensureSchema(db: InstanceType<typeof BetterSqlite3>): void;
|
|
19
|
+
resolveSlug(db: InstanceType<typeof BetterSqlite3>, workspaceId: string, workspacePath: string): string;
|
|
20
|
+
ensureRow(db: InstanceType<typeof BetterSqlite3>, opts: {
|
|
21
|
+
id: string;
|
|
22
|
+
slug: string;
|
|
23
|
+
name: string;
|
|
24
|
+
workspacePath: string;
|
|
25
|
+
}): void;
|
|
26
|
+
}
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.WorkspaceRepository = void 0;
|
|
7
|
+
const fs_1 = require("fs");
|
|
8
|
+
const path_1 = require("path");
|
|
9
|
+
const os_1 = require("os");
|
|
10
|
+
const better_sqlite3_1 = __importDefault(require("better-sqlite3"));
|
|
11
|
+
const sdk_1 = require("@crewx/sdk");
|
|
12
|
+
class WorkspaceRepository {
|
|
13
|
+
dbPath;
|
|
14
|
+
constructor(opts = {}) {
|
|
15
|
+
this.dbPath = (0, path_1.join)(opts.dbRoot ?? (0, os_1.homedir)(), '.crewx', 'crewx.db');
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Register a CLI workspace in the global CrewX DB.
|
|
19
|
+
*
|
|
20
|
+
* This is intentionally CLI-owned, not SDK-owned: workspace registration is
|
|
21
|
+
* CrewX application metadata, while the SDK only needs pure workspace helpers.
|
|
22
|
+
* Registration is best-effort so `crewx init` remains usable even if tracing
|
|
23
|
+
* DB setup fails.
|
|
24
|
+
*/
|
|
25
|
+
registerWorkspace(workspacePath) {
|
|
26
|
+
const normalizedPath = (0, sdk_1.normalizeWorkspacePath)(workspacePath);
|
|
27
|
+
try {
|
|
28
|
+
const dbDir = (0, path_1.dirname)(this.dbPath);
|
|
29
|
+
if (!(0, fs_1.existsSync)(dbDir)) {
|
|
30
|
+
(0, fs_1.mkdirSync)(dbDir, { recursive: true });
|
|
31
|
+
}
|
|
32
|
+
const db = new better_sqlite3_1.default(this.dbPath);
|
|
33
|
+
try {
|
|
34
|
+
this.ensureSchema(db);
|
|
35
|
+
const id = (0, sdk_1.hashWorkspaceId)(normalizedPath);
|
|
36
|
+
const name = (0, path_1.basename)(normalizedPath);
|
|
37
|
+
const slug = this.resolveSlug(db, id, normalizedPath);
|
|
38
|
+
this.ensureRow(db, { id, slug, name, workspacePath: normalizedPath });
|
|
39
|
+
}
|
|
40
|
+
finally {
|
|
41
|
+
db.close();
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
catch {
|
|
45
|
+
// Non-fatal: workspace registration must never crash `crewx init`.
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
ensureSchema(db) {
|
|
49
|
+
db.exec(`
|
|
50
|
+
CREATE TABLE IF NOT EXISTS workspaces (
|
|
51
|
+
id TEXT PRIMARY KEY,
|
|
52
|
+
slug TEXT NOT NULL UNIQUE,
|
|
53
|
+
name TEXT NOT NULL,
|
|
54
|
+
workspace_path TEXT,
|
|
55
|
+
is_active INTEGER NOT NULL DEFAULT 1,
|
|
56
|
+
created_at TEXT NOT NULL,
|
|
57
|
+
updated_at TEXT NOT NULL
|
|
58
|
+
)
|
|
59
|
+
`);
|
|
60
|
+
db.exec(`
|
|
61
|
+
CREATE TABLE IF NOT EXISTS threads (
|
|
62
|
+
id TEXT PRIMARY KEY,
|
|
63
|
+
workspace_id TEXT,
|
|
64
|
+
platform TEXT NOT NULL DEFAULT 'cli',
|
|
65
|
+
title TEXT,
|
|
66
|
+
first_message TEXT,
|
|
67
|
+
last_message TEXT,
|
|
68
|
+
message_count INTEGER NOT NULL DEFAULT 0,
|
|
69
|
+
created_at TEXT NOT NULL,
|
|
70
|
+
updated_at TEXT NOT NULL,
|
|
71
|
+
metadata TEXT,
|
|
72
|
+
FOREIGN KEY (workspace_id) REFERENCES workspaces(id) ON DELETE SET NULL
|
|
73
|
+
)
|
|
74
|
+
`);
|
|
75
|
+
}
|
|
76
|
+
resolveSlug(db, workspaceId, workspacePath) {
|
|
77
|
+
const basenameSlug = (0, path_1.basename)(workspacePath);
|
|
78
|
+
const parentSlug = `${(0, path_1.basename)((0, path_1.dirname)(workspacePath))}/${basenameSlug}`;
|
|
79
|
+
const candidates = [basenameSlug, parentSlug];
|
|
80
|
+
try {
|
|
81
|
+
const slugExistsForOtherWorkspace = (slug) => !!db
|
|
82
|
+
.prepare('SELECT id FROM workspaces WHERE slug = ? AND id != ?')
|
|
83
|
+
.get(slug, workspaceId);
|
|
84
|
+
for (const slug of candidates) {
|
|
85
|
+
if (!slugExistsForOtherWorkspace(slug))
|
|
86
|
+
return slug;
|
|
87
|
+
}
|
|
88
|
+
for (let suffix = 2; suffix < 1000; suffix += 1) {
|
|
89
|
+
const slug = `${parentSlug}-${suffix}`;
|
|
90
|
+
if (!slugExistsForOtherWorkspace(slug))
|
|
91
|
+
return slug;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
catch {
|
|
95
|
+
// workspaces table may not yet exist during early migration.
|
|
96
|
+
}
|
|
97
|
+
return basenameSlug;
|
|
98
|
+
}
|
|
99
|
+
ensureRow(db, opts) {
|
|
100
|
+
const { id, slug, name, workspacePath } = opts;
|
|
101
|
+
const now = new Date().toISOString();
|
|
102
|
+
db.prepare(`
|
|
103
|
+
INSERT OR IGNORE INTO workspaces (id, slug, name, workspace_path, is_active, created_at, updated_at)
|
|
104
|
+
VALUES (?, ?, ?, ?, 1, ?, ?)
|
|
105
|
+
`).run(id, slug, name, workspacePath, now, now);
|
|
106
|
+
db.prepare(`
|
|
107
|
+
UPDATE workspaces SET workspace_path = ?, updated_at = ? WHERE id = ? AND workspace_path IS NULL
|
|
108
|
+
`).run(workspacePath, now, id);
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
exports.WorkspaceRepository = WorkspaceRepository;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@crewx/cli",
|
|
3
|
-
"version": "0.8.2-rc.
|
|
3
|
+
"version": "0.8.2-rc.4",
|
|
4
4
|
"license": "UNLICENSED",
|
|
5
5
|
"engines": {
|
|
6
6
|
"node": ">=20.19.0"
|
|
@@ -27,15 +27,15 @@
|
|
|
27
27
|
"dependencies": {
|
|
28
28
|
"@crewx/adapter-slack": "^0.1.4",
|
|
29
29
|
"better-sqlite3": "*",
|
|
30
|
-
"@crewx/
|
|
30
|
+
"@crewx/doc": "0.1.7",
|
|
31
31
|
"@crewx/search": "0.1.8",
|
|
32
|
+
"@crewx/sdk": "0.8.2-rc.4",
|
|
33
|
+
"@crewx/skill": "0.1.7",
|
|
34
|
+
"@crewx/workflow": "0.3.10",
|
|
32
35
|
"@crewx/memory": "0.1.9",
|
|
33
|
-
"@crewx/
|
|
36
|
+
"@crewx/shared": "0.0.4",
|
|
34
37
|
"@crewx/wbs": "0.1.8",
|
|
35
|
-
"@crewx/cron": "0.1.7"
|
|
36
|
-
"@crewx/workflow": "0.3.8",
|
|
37
|
-
"@crewx/skill": "0.1.7",
|
|
38
|
-
"@crewx/shared": "0.0.4"
|
|
38
|
+
"@crewx/cron": "0.1.7"
|
|
39
39
|
},
|
|
40
40
|
"devDependencies": {
|
|
41
41
|
"@types/better-sqlite3": "*",
|