crewx 0.8.0-rc.80 → 0.8.0-rc.82

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.
@@ -47,6 +47,7 @@ const bridge_1 = require("../provider/bridge");
47
47
  const engine_1 = require("../template/engine");
48
48
  const DocumentLoader_1 = require("../template/loader/DocumentLoader");
49
49
  const loader_2 = require("../layout/loader");
50
+ const paths_1 = require("../paths");
50
51
  const renderer_1 = require("../layout/renderer");
51
52
  const id_1 = require("../utils/id");
52
53
  const timestamp_1 = require("../utils/timestamp");
@@ -87,10 +88,6 @@ function generateSecurityKey() {
87
88
  return randomBytes(8).toString('hex');
88
89
  }
89
90
  }
90
- /**
91
- * Build the default SDK templates path.
92
- */
93
- const SDK_TEMPLATES_PATH = (0, path_1.join)(__dirname, '../../templates/agents');
94
91
  class Crewx extends TypedEventEmitter_1.TypedEventEmitter {
95
92
  _agents;
96
93
  _templateEngine;
@@ -131,7 +128,7 @@ class Crewx extends TypedEventEmitter_1.TypedEventEmitter {
131
128
  execPolicy: options.execPolicy ?? settingsPolicy,
132
129
  });
133
130
  this._documentLoader = documentLoader ?? new DocumentLoader_1.DocumentLoader();
134
- this._layoutLoader = new loader_2.LayoutLoader({ templatesPath: SDK_TEMPLATES_PATH });
131
+ this._layoutLoader = new loader_2.LayoutLoader({ templatesPath: (0, paths_1.resolveTemplatesPath)() });
135
132
  this._layoutRenderer = new renderer_1.LayoutRenderer();
136
133
  this._remoteFactory = options.remoteFactory;
137
134
  }
@@ -42,12 +42,12 @@ exports.LayoutLoader = void 0;
42
42
  const fs_1 = require("fs");
43
43
  const path = __importStar(require("path"));
44
44
  const js_yaml_1 = require("js-yaml");
45
+ const paths_1 = require("../paths");
45
46
  const types_1 = require("./types");
46
47
  /**
47
- * Default loader options — points to SDK's bundled templates directory.
48
+ * Default loader options — templates path resolved at construction time.
48
49
  */
49
50
  const DEFAULT_OPTIONS = {
50
- templatesPath: path.join(__dirname, '../../../templates/agents'),
51
51
  validationMode: 'lenient',
52
52
  fallbackLayoutId: 'crewx/default',
53
53
  };
@@ -60,7 +60,11 @@ class LayoutLoader {
60
60
  layouts = new Map();
61
61
  options;
62
62
  constructor(options) {
63
- this.options = { ...DEFAULT_OPTIONS, ...options };
63
+ this.options = {
64
+ ...DEFAULT_OPTIONS,
65
+ ...options,
66
+ templatesPath: options?.templatesPath ?? (0, paths_1.resolveTemplatesPath)(),
67
+ };
64
68
  this.loadAllLayouts();
65
69
  }
66
70
  /**
@@ -0,0 +1,51 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.resolveTemplatesPath = resolveTemplatesPath;
4
+ const fs_1 = require("fs");
5
+ const path_1 = require("path");
6
+ const module_1 = require("module");
7
+ const TEMPLATES_SUBPATH = (0, path_1.join)('templates', 'agents');
8
+ function tryPackageAnchor() {
9
+ try {
10
+ const req = typeof require === 'function'
11
+ ? require
12
+ : (0, module_1.createRequire)(typeof __filename !== 'undefined' ? __filename : process.cwd() + '/');
13
+ const pkgJson = req.resolve('@crewx/sdk/package.json');
14
+ return (0, path_1.dirname)(pkgJson);
15
+ }
16
+ catch {
17
+ return null;
18
+ }
19
+ }
20
+ /**
21
+ * Resolve the SDK's templates/agents directory.
22
+ * Priority: override → env → package anchor → __dirname walk-up → throw.
23
+ */
24
+ function resolveTemplatesPath(override) {
25
+ if (override && (0, fs_1.existsSync)(override))
26
+ return override;
27
+ const envPath = process.env.CREWX_SDK_TEMPLATES_PATH;
28
+ if (envPath && (0, fs_1.existsSync)(envPath))
29
+ return envPath;
30
+ const pkgRoot = tryPackageAnchor();
31
+ if (pkgRoot) {
32
+ const candidate = (0, path_1.join)(pkgRoot, TEMPLATES_SUBPATH);
33
+ if ((0, fs_1.existsSync)(candidate))
34
+ return candidate;
35
+ }
36
+ const candidates = [
37
+ (0, path_1.join)(__dirname, '..', TEMPLATES_SUBPATH), // dist/index.js (bundled)
38
+ (0, path_1.join)(__dirname, '..', '..', TEMPLATES_SUBPATH), // dist/facade/Crewx.js (tsc)
39
+ (0, path_1.join)(__dirname, '..', '..', '..', TEMPLATES_SUBPATH), // src/layout/loader.ts (vitest)
40
+ (0, path_1.join)(process.cwd(), 'packages', 'sdk', TEMPLATES_SUBPATH),
41
+ (0, path_1.join)(process.cwd(), TEMPLATES_SUBPATH),
42
+ ];
43
+ for (const c of candidates) {
44
+ if ((0, fs_1.existsSync)(c))
45
+ return c;
46
+ }
47
+ throw new Error(`[@crewx/sdk] Templates directory not found.\n` +
48
+ (pkgRoot ? ` package anchor: ${(0, path_1.join)(pkgRoot, TEMPLATES_SUBPATH)}\n` : ' package anchor: (unresolved)\n') +
49
+ candidates.map((p) => ` candidate: ${p}`).join('\n') +
50
+ `\nSet CREWX_SDK_TEMPLATES_PATH or pass options.templatesPath.`);
51
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "crewx",
3
- "version": "0.8.0-rc.80",
3
+ "version": "0.8.0-rc.82",
4
4
  "description": "CrewX — AI agent team dashboard with Electron UI and CLI (Web + Electron + Global CLI)",
5
5
  "main": "server.js",
6
6
  "bin": {
@@ -19,11 +19,7 @@
19
19
  "!**/__tests__",
20
20
  "!**/*.test.*",
21
21
  "!**/*.spec.*",
22
- "!**/*.js.map",
23
- "!**/*.d.ts.map",
24
- "!scripts/**/*.ts",
25
- "!packages/cli/dist/**/*.spec.*",
26
- "!packages/cli/dist/**/*.test.*"
22
+ "!scripts/**/*.ts"
27
23
  ],
28
24
  "author": {
29
25
  "name": "Doha Park",
@@ -96,16 +92,16 @@
96
92
  "yargs": "^17.7.0",
97
93
  "zod": "^3.22.0",
98
94
  "zustand": "^4.5.0",
99
- "@crewx/cli": "0.8.0-rc.80",
95
+ "@crewx/cli": "0.8.0-rc.82",
100
96
  "@crewx/cron": "0.1.6",
101
97
  "@crewx/doc": "0.1.6",
98
+ "@crewx/sdk": "0.8.0-rc.82",
102
99
  "@crewx/memory": "0.1.8",
103
- "@crewx/sdk": "0.8.0-rc.80",
104
- "@crewx/shared": "0.0.4",
105
100
  "@crewx/search": "0.1.6",
106
- "@crewx/skill": "0.1.5",
101
+ "@crewx/shared": "0.0.4",
102
+ "@crewx/wbs": "0.1.7",
107
103
  "@crewx/workflow": "0.3.6",
108
- "@crewx/wbs": "0.1.7"
104
+ "@crewx/skill": "0.1.5"
109
105
  },
110
106
  "devDependencies": {
111
107
  "@nestjs/cli": "^11.0.16",
@@ -138,11 +134,12 @@
138
134
  "react-dom": "^18.2.0",
139
135
  "supertest": "^7.2.2",
140
136
  "tailwindcss": "^3.3.6",
137
+ "tsup": "^8.5.1",
141
138
  "tsx": "^4.6.2",
142
139
  "typescript": "^5.3.3",
143
140
  "vite": "^5.0.10",
144
141
  "vite-plugin-electron": "^0.29.0",
145
- "vitest": "^3.1.1"
142
+ "vitest": "^4.0.18"
146
143
  },
147
144
  "optionalDependencies": {
148
145
  "electron": "^39.2.7"
@@ -0,0 +1,13 @@
1
+ /**
2
+ * CLI convenience wrapper for SqliteTracingPlugin.
3
+ * Accepts a dbRoot string or an options object so existing CLI tests can pass
4
+ * a temp directory path directly.
5
+ */
6
+ import { SqliteTracingPlugin as SdkPlugin } from '@crewx/sdk/plugins';
7
+ export type { SqliteTracingPluginOptions } from '@crewx/sdk/plugins';
8
+ export declare class SqliteTracingPlugin extends SdkPlugin {
9
+ constructor(dbRootOrOpts?: string | {
10
+ dbRoot?: string;
11
+ version?: string;
12
+ });
13
+ }
@@ -0,0 +1,20 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.SqliteTracingPlugin = void 0;
4
+ /**
5
+ * CLI convenience wrapper for SqliteTracingPlugin.
6
+ * Accepts a dbRoot string or an options object so existing CLI tests can pass
7
+ * a temp directory path directly.
8
+ */
9
+ const plugins_1 = require("@crewx/sdk/plugins");
10
+ class SqliteTracingPlugin extends plugins_1.SqliteTracingPlugin {
11
+ constructor(dbRootOrOpts) {
12
+ if (typeof dbRootOrOpts === 'string') {
13
+ super({ dbRoot: dbRootOrOpts });
14
+ }
15
+ else {
16
+ super(dbRootOrOpts);
17
+ }
18
+ }
19
+ }
20
+ exports.SqliteTracingPlugin = SqliteTracingPlugin;
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@crewx/cli",
3
- "version": "0.8.0-rc.80",
3
+ "version": "0.8.0-rc.82",
4
4
  "license": "UNLICENSED",
5
5
  "engines": {
6
6
  "node": ">=20.19.0"
@@ -0,0 +1,285 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * smoke-tarball.mjs — Tarball-isolated smoke test for crewx CLI.
4
+ *
5
+ * Packs the current project into a tarball, installs it in a temp directory
6
+ * (no global install), and runs a suite of smoke checks against the binary.
7
+ * This avoids workspace symlink false-positives that npm install -g . can produce.
8
+ *
9
+ * Usage:
10
+ * node scripts/smoke-tarball.mjs [--version <expected>] [--skip-web]
11
+ *
12
+ * Flags:
13
+ * --version <ver> Expected crewx --version output. Defaults to package.json version.
14
+ * --skip-web Skip the NestJS web server startup check (useful in CI).
15
+ * --timeout <ms> Per-command timeout in ms. Default: 15000.
16
+ *
17
+ * Exit code: 0 = ALL PASS, 1 = one or more FAILs.
18
+ */
19
+
20
+ import { execFileSync, spawnSync } from 'child_process';
21
+ import { mkdtempSync, rmSync, writeFileSync, mkdirSync } from 'fs';
22
+ import { join, resolve } from 'path';
23
+ import { tmpdir } from 'os';
24
+ import { createRequire } from 'module';
25
+
26
+ const require = createRequire(import.meta.url);
27
+ const rootPkg = require('../package.json');
28
+
29
+ // ── CLI args ──────────────────────────────────────────────────────────────────
30
+ const args = process.argv.slice(2);
31
+ const getArg = (flag) => {
32
+ const i = args.indexOf(flag);
33
+ return i !== -1 ? args[i + 1] : null;
34
+ };
35
+ const hasFlag = (flag) => args.includes(flag);
36
+
37
+ const expectedVersion = getArg('--version') ?? rootPkg.version;
38
+ const skipWeb = hasFlag('--skip-web');
39
+ const cmdTimeout = parseInt(getArg('--timeout') ?? '15000', 10);
40
+
41
+ // ── Result tracking ───────────────────────────────────────────────────────────
42
+ const results = [];
43
+ let anyFail = false;
44
+
45
+ function pass(label) {
46
+ results.push({ label, status: 'PASS' });
47
+ console.log(` ✓ PASS ${label}`);
48
+ }
49
+
50
+ function fail(label, detail = '') {
51
+ results.push({ label, status: 'FAIL', detail });
52
+ console.error(` ✗ FAIL ${label}${detail ? ': ' + detail : ''}`);
53
+ anyFail = true;
54
+ }
55
+
56
+ function run(cmd, cmdArgs, opts = {}) {
57
+ const result = spawnSync(cmd, cmdArgs, {
58
+ timeout: opts.timeout ?? cmdTimeout,
59
+ encoding: 'utf8',
60
+ cwd: opts.cwd,
61
+ env: { ...process.env, ...opts.env },
62
+ });
63
+ return {
64
+ stdout: result.stdout ?? '',
65
+ stderr: result.stderr ?? '',
66
+ status: result.status ?? -1,
67
+ timedOut: result.signal === 'SIGTERM',
68
+ };
69
+ }
70
+
71
+ // ── Step 1: Pack ──────────────────────────────────────────────────────────────
72
+ const packDest = tmpdir();
73
+ console.log('\n[1/3] Packing tarball...');
74
+ let tarball;
75
+ try {
76
+ const out = execFileSync('pnpm', ['pack', '--pack-destination', packDest], {
77
+ cwd: resolve('.'),
78
+ encoding: 'utf8',
79
+ }).trim();
80
+ tarball = out.split('\n').pop().trim();
81
+ console.log(` Tarball: ${tarball}`);
82
+ } catch (e) {
83
+ console.error('FATAL: pnpm pack failed:', e.message);
84
+ process.exit(1);
85
+ }
86
+
87
+ // ── Step 2: Install in temp dir ───────────────────────────────────────────────
88
+ const installDir = mkdtempSync(join(tmpdir(), 'crewx-smoke-install-'));
89
+ console.log(`\n[2/3] Installing into ${installDir}...`);
90
+ try {
91
+ execFileSync('npm', ['install', tarball], {
92
+ cwd: installDir,
93
+ encoding: 'utf8',
94
+ stdio: 'inherit',
95
+ });
96
+ } catch (e) {
97
+ console.error('FATAL: npm install failed:', e.message);
98
+ rmSync(installDir, { recursive: true, force: true });
99
+ process.exit(1);
100
+ }
101
+
102
+ const binDir = join(installDir, 'node_modules', '.bin');
103
+ const env = { ...process.env, PATH: `${binDir}:${process.env.PATH}` };
104
+
105
+ // ── Step 3: Test dir (clean workspace) ────────────────────────────────────────
106
+ const testDir = mkdtempSync(join(tmpdir(), 'crewx-smoke-test-'));
107
+ mkdirSync(join(testDir, '.git')); // minimal git marker
108
+
109
+ // Minimal crewx.yaml for agent tests
110
+ writeFileSync(join(testDir, 'crewx.yaml'), `
111
+ agents:
112
+ - id: crewx
113
+ name: "CrewX Assistant"
114
+ inline:
115
+ provider: "cli/claude"
116
+ prompt: "You are a test agent. Reply with OK only."
117
+ `.trim());
118
+
119
+ console.log(`\n[3/3] Running smoke checks from ${testDir}...\n`);
120
+
121
+ // ── Check 1: version ──────────────────────────────────────────────────────────
122
+ {
123
+ const r = run('crewx', ['--version'], { cwd: testDir, env });
124
+ const actual = r.stdout.trim();
125
+ if (actual === expectedVersion) {
126
+ pass(`crewx --version == ${expectedVersion}`);
127
+ } else {
128
+ fail('crewx --version', `expected "${expectedVersion}", got "${actual}"`);
129
+ }
130
+ }
131
+
132
+ // ── Check 2: help ─────────────────────────────────────────────────────────────
133
+ {
134
+ const r = run('crewx', ['--help'], { cwd: testDir, env });
135
+ if (r.status === 0 && r.stdout.includes(expectedVersion)) {
136
+ pass('crewx --help shows correct version');
137
+ } else {
138
+ fail('crewx --help', `exit=${r.status}, version in output: ${r.stdout.includes(expectedVersion)}`);
139
+ }
140
+ }
141
+
142
+ // ── Check 3: agent list ───────────────────────────────────────────────────────
143
+ {
144
+ const r = run('crewx', ['agent', 'list'], { cwd: testDir, env });
145
+ if (r.status === 0) {
146
+ pass('crewx agent list');
147
+ } else {
148
+ fail('crewx agent list', r.stderr.slice(0, 200));
149
+ }
150
+ }
151
+
152
+ // ── Check 4: skill list ───────────────────────────────────────────────────────
153
+ {
154
+ const r = run('crewx', ['skill', 'list'], { cwd: testDir, env });
155
+ if (r.status === 0 || r.stdout.includes('No skills')) {
156
+ pass('crewx skill list');
157
+ } else {
158
+ fail('crewx skill list', r.stderr.slice(0, 200));
159
+ }
160
+ }
161
+
162
+ // ── Check 5: memory --help ────────────────────────────────────────────────────
163
+ {
164
+ const r = run('crewx', ['memory', '--help'], { cwd: testDir, env });
165
+ if (r.status === 0) {
166
+ pass('crewx memory --help');
167
+ } else {
168
+ fail('crewx memory --help', r.stderr.slice(0, 200));
169
+ }
170
+ }
171
+
172
+ // ── Check 6: workflow --help ──────────────────────────────────────────────────
173
+ {
174
+ const r = run('crewx', ['workflow', '--help'], { cwd: testDir, env });
175
+ if (r.status === 0) {
176
+ pass('crewx workflow --help');
177
+ } else {
178
+ fail('crewx workflow --help', r.stderr.slice(0, 200));
179
+ }
180
+ }
181
+
182
+ // ── Check 7: search ───────────────────────────────────────────────────────────
183
+ {
184
+ const r = run('crewx', ['search', 'test', '.'], { cwd: testDir, env, timeout: 10000 });
185
+ const noError = !r.stderr.includes('ERR_MODULE_NOT_FOUND') && !r.stderr.includes('is not a function');
186
+ if (noError) {
187
+ pass('crewx search (no crash)');
188
+ } else {
189
+ fail('crewx search', r.stderr.slice(0, 300));
190
+ }
191
+ }
192
+
193
+ // ── Check 8: crewx q "hi" (SDK loading check) ────────────────────────────────
194
+ {
195
+ const r = run('crewx', ['q', 'hi'], { cwd: testDir, env, timeout: 15000 });
196
+ const combined = r.stdout + r.stderr;
197
+ const sdkErrors = ['ERR_MODULE_NOT_FOUND', 'is not a function', 'Cannot find module'];
198
+ const hasError = sdkErrors.some(e => combined.includes(e));
199
+ if (!hasError) {
200
+ pass('crewx q "hi" (no SDK import errors)');
201
+ } else {
202
+ const found = sdkErrors.find(e => combined.includes(e));
203
+ fail('crewx q "hi"', `SDK error: ${found}`);
204
+ }
205
+ }
206
+
207
+ // ── Check 9: crewx web startup ────────────────────────────────────────────────
208
+ if (!skipWeb) {
209
+ const r = run('crewx', [], { cwd: testDir, env, timeout: 10000 });
210
+ const combined = r.stdout + r.stderr;
211
+ const hasModuleError = combined.includes('ERR_MODULE_NOT_FOUND');
212
+ if (!hasModuleError) {
213
+ pass('crewx (web) startup — no ERR_MODULE_NOT_FOUND');
214
+ } else {
215
+ fail('crewx (web) startup', 'ERR_MODULE_NOT_FOUND detected');
216
+ }
217
+ } else {
218
+ console.log(' - SKIP crewx web startup (--skip-web)');
219
+ }
220
+
221
+ // ── Check 10: SDK templates load (CJS require) ───────────────────────────────
222
+ {
223
+ const sdkDir = join(installDir, 'node_modules', '@crewx', 'sdk');
224
+ const r = run('node', ['-e', `
225
+ const { existsSync, readdirSync } = require('fs');
226
+ const { join, dirname } = require('path');
227
+ const sdkMain = require.resolve('${sdkDir.replace(/\\/g, '/')}/dist/index.js');
228
+ const distDir = dirname(sdkMain);
229
+ const templatesPath = join(distDir, '../templates/agents');
230
+ if (!existsSync(templatesPath)) { process.stdout.write('FAIL: ' + templatesPath + '\\n'); process.exit(1); }
231
+ const files = readdirSync(templatesPath);
232
+ if (!files.includes('default.yaml')) { process.stdout.write('FAIL: default.yaml missing\\n'); process.exit(1); }
233
+ process.stdout.write('OK: ' + templatesPath + '\\n');
234
+ `], { cwd: testDir, env, timeout: 5000 });
235
+ if (r.status === 0 && r.stdout.includes('OK:')) {
236
+ pass('SDK templates load (CJS) — dist/index.js → ../templates/agents ✓');
237
+ } else {
238
+ fail('SDK templates load (CJS)', r.stderr.slice(0, 200) || r.stdout.slice(0, 200));
239
+ }
240
+ }
241
+
242
+ // ── Check 11: SDK templates load (ESM import — same dist/index.js via exports) ─
243
+ {
244
+ const sdkDir = join(installDir, 'node_modules', '@crewx', 'sdk');
245
+ const r = run('node', ['--input-type=module', '--eval', `
246
+ import { existsSync, readdirSync } from 'fs';
247
+ import { join, dirname } from 'path';
248
+ import { createRequire } from 'module';
249
+ const require = createRequire(import.meta.url);
250
+ // "import" condition in package.json exports also points to dist/index.js (CJS)
251
+ const sdkMain = require.resolve('${sdkDir.replace(/\\/g, '/')}/dist/index.js');
252
+ const distDir = dirname(sdkMain);
253
+ const templatesPath = join(distDir, '../templates/agents');
254
+ if (!existsSync(templatesPath)) { process.stdout.write('FAIL: ' + templatesPath + '\\n'); process.exit(1); }
255
+ const files = readdirSync(templatesPath);
256
+ if (!files.includes('default.yaml')) { process.stdout.write('FAIL: default.yaml missing\\n'); process.exit(1); }
257
+ process.stdout.write('OK: ' + templatesPath + '\\n');
258
+ `], { cwd: testDir, env, timeout: 5000 });
259
+ if (r.status === 0 && r.stdout.includes('OK:')) {
260
+ pass('SDK templates load (ESM) — dist/index.js → ../templates/agents ✓');
261
+ } else {
262
+ fail('SDK templates load (ESM)', r.stderr.slice(0, 200) || r.stdout.slice(0, 200));
263
+ }
264
+ }
265
+
266
+ // ── Cleanup ───────────────────────────────────────────────────────────────────
267
+ rmSync(testDir, { recursive: true, force: true });
268
+ rmSync(installDir, { recursive: true, force: true });
269
+ try { rmSync(tarball, { force: true }); } catch {}
270
+
271
+ // ── Summary ───────────────────────────────────────────────────────────────────
272
+ console.log('\n' + '─'.repeat(60));
273
+ const passed = results.filter(r => r.status === 'PASS').length;
274
+ const failed = results.filter(r => r.status === 'FAIL').length;
275
+
276
+ if (!anyFail) {
277
+ console.log(`✅ ALL PASS (${passed}/${results.length})`);
278
+ } else {
279
+ console.log(`❌ ${failed} FAIL / ${passed} PASS`);
280
+ results.filter(r => r.status === 'FAIL').forEach(r => {
281
+ console.error(` FAIL: ${r.label}${r.detail ? ' — ' + r.detail : ''}`);
282
+ });
283
+ }
284
+
285
+ process.exit(anyFail ? 1 : 0);