@sena-ai/cli 0.0.15
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/dist/__tests__/config-loader.test.d.ts +2 -0
- package/dist/__tests__/config-loader.test.d.ts.map +1 -0
- package/dist/__tests__/config-loader.test.js +57 -0
- package/dist/__tests__/config-loader.test.js.map +1 -0
- package/dist/__tests__/pid.test.d.ts +2 -0
- package/dist/__tests__/pid.test.d.ts.map +1 -0
- package/dist/__tests__/pid.test.js +23 -0
- package/dist/__tests__/pid.test.js.map +1 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +27 -0
- package/dist/cli.js.map +1 -0
- package/dist/commands/logs.d.ts +3 -0
- package/dist/commands/logs.d.ts.map +1 -0
- package/dist/commands/logs.js +34 -0
- package/dist/commands/logs.js.map +1 -0
- package/dist/commands/restart.d.ts +3 -0
- package/dist/commands/restart.d.ts.map +1 -0
- package/dist/commands/restart.js +92 -0
- package/dist/commands/restart.js.map +1 -0
- package/dist/commands/start.d.ts +3 -0
- package/dist/commands/start.d.ts.map +1 -0
- package/dist/commands/start.js +91 -0
- package/dist/commands/start.js.map +1 -0
- package/dist/commands/status.d.ts +3 -0
- package/dist/commands/status.d.ts.map +1 -0
- package/dist/commands/status.js +58 -0
- package/dist/commands/status.js.map +1 -0
- package/dist/commands/stop.d.ts +3 -0
- package/dist/commands/stop.d.ts.map +1 -0
- package/dist/commands/stop.js +45 -0
- package/dist/commands/stop.js.map +1 -0
- package/dist/config-loader.d.ts +7 -0
- package/dist/config-loader.d.ts.map +1 -0
- package/dist/config-loader.js +41 -0
- package/dist/config-loader.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -0
- package/dist/pid.d.ts +5 -0
- package/dist/pid.d.ts.map +1 -0
- package/dist/pid.js +34 -0
- package/dist/pid.js.map +1 -0
- package/dist/worker-entry.d.ts +2 -0
- package/dist/worker-entry.d.ts.map +1 -0
- package/dist/worker-entry.js +22 -0
- package/dist/worker-entry.js.map +1 -0
- package/package.json +31 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config-loader.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/config-loader.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { mkdtempSync, mkdirSync, realpathSync, writeFileSync } from 'node:fs';
|
|
2
|
+
import { tmpdir } from 'node:os';
|
|
3
|
+
import { join } from 'node:path';
|
|
4
|
+
import { afterEach, describe, expect, it } from 'vitest';
|
|
5
|
+
import { loadConfig } from '../config-loader.js';
|
|
6
|
+
const createdDirs = [];
|
|
7
|
+
function createTempAgentDir() {
|
|
8
|
+
const dir = mkdtempSync(join(tmpdir(), 'sena-cli-'));
|
|
9
|
+
createdDirs.push(dir);
|
|
10
|
+
return dir;
|
|
11
|
+
}
|
|
12
|
+
describe('loadConfig', () => {
|
|
13
|
+
afterEach(() => {
|
|
14
|
+
delete process.env.SENA_PORT;
|
|
15
|
+
});
|
|
16
|
+
it('loads sena.config.ts and .env from the current working directory', async () => {
|
|
17
|
+
const dir = createTempAgentDir();
|
|
18
|
+
mkdirSync(join(dir, '.sena'));
|
|
19
|
+
writeFileSync(join(dir, '.env'), 'SENA_PORT=4567\n', 'utf-8');
|
|
20
|
+
writeFileSync(join(dir, 'sena.config.ts'), [
|
|
21
|
+
'export default {',
|
|
22
|
+
" name: 'test-agent',",
|
|
23
|
+
' orchestrator: { port: 1234 },',
|
|
24
|
+
'}',
|
|
25
|
+
].join('\n'), 'utf-8');
|
|
26
|
+
const previousCwd = process.cwd();
|
|
27
|
+
process.chdir(dir);
|
|
28
|
+
try {
|
|
29
|
+
const result = await loadConfig();
|
|
30
|
+
expect(result.config.name).toBe('test-agent');
|
|
31
|
+
expect(result.port).toBe(1234);
|
|
32
|
+
expect(realpathSync(result.configPath)).toBe(realpathSync(join(dir, 'sena.config.ts')));
|
|
33
|
+
}
|
|
34
|
+
finally {
|
|
35
|
+
process.chdir(previousCwd);
|
|
36
|
+
}
|
|
37
|
+
});
|
|
38
|
+
it('falls back to SENA_PORT when config port is missing', async () => {
|
|
39
|
+
const dir = createTempAgentDir();
|
|
40
|
+
writeFileSync(join(dir, '.env'), 'SENA_PORT=4567\n', 'utf-8');
|
|
41
|
+
writeFileSync(join(dir, 'sena.config.ts'), [
|
|
42
|
+
'export default {',
|
|
43
|
+
" name: 'port-from-env',",
|
|
44
|
+
'}',
|
|
45
|
+
].join('\n'), 'utf-8');
|
|
46
|
+
const previousCwd = process.cwd();
|
|
47
|
+
process.chdir(dir);
|
|
48
|
+
try {
|
|
49
|
+
const result = await loadConfig();
|
|
50
|
+
expect(result.port).toBe(4567);
|
|
51
|
+
}
|
|
52
|
+
finally {
|
|
53
|
+
process.chdir(previousCwd);
|
|
54
|
+
}
|
|
55
|
+
});
|
|
56
|
+
});
|
|
57
|
+
//# sourceMappingURL=config-loader.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config-loader.test.js","sourceRoot":"","sources":["../../src/__tests__/config-loader.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pid.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/pid.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { mkdtempSync } from 'node:fs';
|
|
2
|
+
import { tmpdir } from 'node:os';
|
|
3
|
+
import { join } from 'node:path';
|
|
4
|
+
import { describe, expect, it } from 'vitest';
|
|
5
|
+
import { isProcessAlive, readPid, removePid, writePid } from '../pid.js';
|
|
6
|
+
describe('pid helpers', () => {
|
|
7
|
+
it('writes, reads, and removes the pid file in the current directory', () => {
|
|
8
|
+
const dir = mkdtempSync(join(tmpdir(), 'sena-pid-'));
|
|
9
|
+
const previousCwd = process.cwd();
|
|
10
|
+
process.chdir(dir);
|
|
11
|
+
try {
|
|
12
|
+
writePid(process.pid);
|
|
13
|
+
expect(readPid()).toBe(process.pid);
|
|
14
|
+
expect(isProcessAlive(process.pid)).toBe(true);
|
|
15
|
+
removePid();
|
|
16
|
+
expect(readPid()).toBeNull();
|
|
17
|
+
}
|
|
18
|
+
finally {
|
|
19
|
+
process.chdir(previousCwd);
|
|
20
|
+
}
|
|
21
|
+
});
|
|
22
|
+
});
|
|
23
|
+
//# sourceMappingURL=pid.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pid.test.js","sourceRoot":"","sources":["../../src/__tests__/pid.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,SAAS,CAAA;AACrC,OAAO,EAAE,MAAM,EAAE,MAAM,SAAS,CAAA;AAChC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAA;AAChC,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAA;AAE7C,OAAO,EAAE,cAAc,EAAE,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAA;AAExE,QAAQ,CAAC,aAAa,EAAE,GAAG,EAAE;IAC3B,EAAE,CAAC,kEAAkE,EAAE,GAAG,EAAE;QAC1E,MAAM,GAAG,GAAG,WAAW,CAAC,IAAI,CAAC,MAAM,EAAE,EAAE,WAAW,CAAC,CAAC,CAAA;QACpD,MAAM,WAAW,GAAG,OAAO,CAAC,GAAG,EAAE,CAAA;QACjC,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,CAAA;QAElB,IAAI,CAAC;YACH,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,CAAA;YACrB,MAAM,CAAC,OAAO,EAAE,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,CAAA;YACnC,MAAM,CAAC,cAAc,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;YAE9C,SAAS,EAAE,CAAA;YACX,MAAM,CAAC,OAAO,EAAE,CAAC,CAAC,QAAQ,EAAE,CAAA;QAC9B,CAAC;gBAAS,CAAC;YACT,OAAO,CAAC,KAAK,CAAC,WAAW,CAAC,CAAA;QAC5B,CAAC;IACH,CAAC,CAAC,CAAA;AACJ,CAAC,CAAC,CAAA"}
|
package/dist/cli.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":""}
|
package/dist/cli.js
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { Command } from 'commander';
|
|
3
|
+
import { readFileSync } from 'node:fs';
|
|
4
|
+
import { fileURLToPath } from 'node:url';
|
|
5
|
+
import { dirname, resolve } from 'node:path';
|
|
6
|
+
import { registerStart } from './commands/start.js';
|
|
7
|
+
import { registerStop } from './commands/stop.js';
|
|
8
|
+
import { registerRestart } from './commands/restart.js';
|
|
9
|
+
import { registerStatus } from './commands/status.js';
|
|
10
|
+
import { registerLogs } from './commands/logs.js';
|
|
11
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
12
|
+
const __dirname = dirname(__filename);
|
|
13
|
+
// Read version from package.json
|
|
14
|
+
const pkg = JSON.parse(readFileSync(resolve(__dirname, '..', 'package.json'), 'utf-8'));
|
|
15
|
+
const program = new Command();
|
|
16
|
+
program
|
|
17
|
+
.name('sena')
|
|
18
|
+
.description('Sena AI agent lifecycle manager')
|
|
19
|
+
.version(pkg.version)
|
|
20
|
+
.option('-c, --config <path>', 'path to sena.config.ts');
|
|
21
|
+
registerStart(program);
|
|
22
|
+
registerStop(program);
|
|
23
|
+
registerRestart(program);
|
|
24
|
+
registerStatus(program);
|
|
25
|
+
registerLogs(program);
|
|
26
|
+
program.parse();
|
|
27
|
+
//# sourceMappingURL=cli.js.map
|
package/dist/cli.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AACnC,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAA;AACtC,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAA;AACxC,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AAE5C,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAA;AACnD,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAA;AACjD,OAAO,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAA;AACvD,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAA;AACrD,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAA;AAEjD,MAAM,UAAU,GAAG,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAA;AACjD,MAAM,SAAS,GAAG,OAAO,CAAC,UAAU,CAAC,CAAA;AAErC,iCAAiC;AACjC,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,OAAO,CAAC,SAAS,EAAE,IAAI,EAAE,cAAc,CAAC,EAAE,OAAO,CAAC,CAAwB,CAAA;AAE9G,MAAM,OAAO,GAAG,IAAI,OAAO,EAAE,CAAA;AAE7B,OAAO;KACJ,IAAI,CAAC,MAAM,CAAC;KACZ,WAAW,CAAC,iCAAiC,CAAC;KAC9C,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC;KACpB,MAAM,CAAC,qBAAqB,EAAE,wBAAwB,CAAC,CAAA;AAE1D,aAAa,CAAC,OAAO,CAAC,CAAA;AACtB,YAAY,CAAC,OAAO,CAAC,CAAA;AACrB,eAAe,CAAC,OAAO,CAAC,CAAA;AACxB,cAAc,CAAC,OAAO,CAAC,CAAA;AACvB,YAAY,CAAC,OAAO,CAAC,CAAA;AAErB,OAAO,CAAC,KAAK,EAAE,CAAA"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"logs.d.ts","sourceRoot":"","sources":["../../src/commands/logs.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AAKxC,wBAAgB,YAAY,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAkCnD"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { spawn } from 'node:child_process';
|
|
2
|
+
import { resolve } from 'node:path';
|
|
3
|
+
import { existsSync } from 'node:fs';
|
|
4
|
+
export function registerLogs(program) {
|
|
5
|
+
program
|
|
6
|
+
.command('logs')
|
|
7
|
+
.description('Show Sena agent logs')
|
|
8
|
+
.option('-f, --follow', 'follow log output (default: true)', true)
|
|
9
|
+
.option('--no-follow', 'do not follow log output')
|
|
10
|
+
.option('-n, --lines <n>', 'number of lines to show', '50')
|
|
11
|
+
.action((opts) => {
|
|
12
|
+
const logPath = resolve(process.cwd(), 'sena.log');
|
|
13
|
+
if (!existsSync(logPath)) {
|
|
14
|
+
console.log('No log file found (sena.log)');
|
|
15
|
+
return;
|
|
16
|
+
}
|
|
17
|
+
const args = ['-n', opts.lines];
|
|
18
|
+
if (opts.follow) {
|
|
19
|
+
args.push('-f');
|
|
20
|
+
}
|
|
21
|
+
args.push(logPath);
|
|
22
|
+
const tail = spawn('tail', args, {
|
|
23
|
+
stdio: ['ignore', 'inherit', 'inherit'],
|
|
24
|
+
});
|
|
25
|
+
process.on('SIGINT', () => {
|
|
26
|
+
tail.kill();
|
|
27
|
+
process.exit(0);
|
|
28
|
+
});
|
|
29
|
+
tail.on('exit', (code) => {
|
|
30
|
+
process.exit(code ?? 0);
|
|
31
|
+
});
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
//# sourceMappingURL=logs.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"logs.js","sourceRoot":"","sources":["../../src/commands/logs.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,KAAK,EAAE,MAAM,oBAAoB,CAAA;AAC1C,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AACnC,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAA;AAEpC,MAAM,UAAU,YAAY,CAAC,OAAgB;IAC3C,OAAO;SACJ,OAAO,CAAC,MAAM,CAAC;SACf,WAAW,CAAC,sBAAsB,CAAC;SACnC,MAAM,CAAC,cAAc,EAAE,mCAAmC,EAAE,IAAI,CAAC;SACjE,MAAM,CAAC,aAAa,EAAE,0BAA0B,CAAC;SACjD,MAAM,CAAC,iBAAiB,EAAE,yBAAyB,EAAE,IAAI,CAAC;SAC1D,MAAM,CAAC,CAAC,IAAwC,EAAE,EAAE;QACnD,MAAM,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,UAAU,CAAC,CAAA;QAElD,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC,EAAE,CAAC;YACzB,OAAO,CAAC,GAAG,CAAC,8BAA8B,CAAC,CAAA;YAC3C,OAAM;QACR,CAAC;QAED,MAAM,IAAI,GAAG,CAAC,IAAI,EAAE,IAAI,CAAC,KAAK,CAAC,CAAA;QAC/B,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC;YAChB,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;QACjB,CAAC;QACD,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,CAAA;QAElB,MAAM,IAAI,GAAG,KAAK,CAAC,MAAM,EAAE,IAAI,EAAE;YAC/B,KAAK,EAAE,CAAC,QAAQ,EAAE,SAAS,EAAE,SAAS,CAAC;SACxC,CAAC,CAAA;QAEF,OAAO,CAAC,EAAE,CAAC,QAAQ,EAAE,GAAG,EAAE;YACxB,IAAI,CAAC,IAAI,EAAE,CAAA;YACX,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;QACjB,CAAC,CAAC,CAAA;QAEF,IAAI,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,EAAE;YACvB,OAAO,CAAC,IAAI,CAAC,IAAI,IAAI,CAAC,CAAC,CAAA;QACzB,CAAC,CAAC,CAAA;IACJ,CAAC,CAAC,CAAA;AACN,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"restart.d.ts","sourceRoot":"","sources":["../../src/commands/restart.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AAGxC,wBAAgB,eAAe,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAatD"}
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import { readPid, isProcessAlive } from '../pid.js';
|
|
2
|
+
export function registerRestart(program) {
|
|
3
|
+
program
|
|
4
|
+
.command('restart')
|
|
5
|
+
.description('Restart the Sena agent')
|
|
6
|
+
.option('--full', 'full restart (stop + start in daemon mode)')
|
|
7
|
+
.option('-c, --config <path>', 'path to sena.config.ts')
|
|
8
|
+
.action(async (opts) => {
|
|
9
|
+
if (opts.full) {
|
|
10
|
+
await fullRestart(program, opts.config);
|
|
11
|
+
}
|
|
12
|
+
else {
|
|
13
|
+
await workerRestart();
|
|
14
|
+
}
|
|
15
|
+
});
|
|
16
|
+
}
|
|
17
|
+
async function workerRestart() {
|
|
18
|
+
const pid = readPid();
|
|
19
|
+
if (pid === null) {
|
|
20
|
+
console.error('No running sena process found');
|
|
21
|
+
process.exit(1);
|
|
22
|
+
}
|
|
23
|
+
if (!isProcessAlive(pid)) {
|
|
24
|
+
console.error(`Process (PID: ${pid}) is not running`);
|
|
25
|
+
process.exit(1);
|
|
26
|
+
}
|
|
27
|
+
process.kill(pid, 'SIGUSR2');
|
|
28
|
+
console.log('Worker restart triggered');
|
|
29
|
+
}
|
|
30
|
+
async function fullRestart(program, configPath) {
|
|
31
|
+
// Execute stop logic
|
|
32
|
+
const pid = readPid();
|
|
33
|
+
if (pid !== null && isProcessAlive(pid)) {
|
|
34
|
+
// Reuse stop logic inline
|
|
35
|
+
process.kill(pid, 'SIGTERM');
|
|
36
|
+
console.log(`Sent SIGTERM to process ${pid}, waiting for shutdown...`);
|
|
37
|
+
const maxWait = 10_000;
|
|
38
|
+
const interval = 100;
|
|
39
|
+
let waited = 0;
|
|
40
|
+
while (waited < maxWait) {
|
|
41
|
+
await new Promise((r) => setTimeout(r, interval));
|
|
42
|
+
waited += interval;
|
|
43
|
+
if (!isProcessAlive(pid))
|
|
44
|
+
break;
|
|
45
|
+
}
|
|
46
|
+
if (isProcessAlive(pid)) {
|
|
47
|
+
try {
|
|
48
|
+
process.kill(pid, 'SIGKILL');
|
|
49
|
+
}
|
|
50
|
+
catch {
|
|
51
|
+
// ignore
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
const { removePid } = await import('../pid.js');
|
|
55
|
+
removePid();
|
|
56
|
+
console.log('Previous instance stopped');
|
|
57
|
+
}
|
|
58
|
+
// Start in daemon mode
|
|
59
|
+
const { loadConfig } = await import('../config-loader.js');
|
|
60
|
+
const globalConfig = program.opts().config;
|
|
61
|
+
const resolvedConfigPath = configPath ?? globalConfig;
|
|
62
|
+
// Simulate daemon start by importing and calling
|
|
63
|
+
const { spawn } = await import('node:child_process');
|
|
64
|
+
const { openSync } = await import('node:fs');
|
|
65
|
+
const { resolve, dirname } = await import('node:path');
|
|
66
|
+
const { fileURLToPath } = await import('node:url');
|
|
67
|
+
const { writePid } = await import('../pid.js');
|
|
68
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
69
|
+
const __dirname = dirname(__filename);
|
|
70
|
+
const { port, configPath: absConfigPath } = await loadConfig(resolvedConfigPath);
|
|
71
|
+
const cliPath = resolve(__dirname, '..', 'cli.js');
|
|
72
|
+
const logPath = resolve(process.cwd(), 'sena.log');
|
|
73
|
+
const logFd = openSync(logPath, 'a');
|
|
74
|
+
const args = ['start'];
|
|
75
|
+
if (absConfigPath) {
|
|
76
|
+
args.push('-c', absConfigPath);
|
|
77
|
+
}
|
|
78
|
+
const child = spawn(process.execPath, [cliPath, ...args], {
|
|
79
|
+
detached: true,
|
|
80
|
+
stdio: ['ignore', logFd, logFd],
|
|
81
|
+
env: { ...process.env, SENA_CONFIG_PATH: absConfigPath },
|
|
82
|
+
});
|
|
83
|
+
child.unref();
|
|
84
|
+
if (child.pid) {
|
|
85
|
+
console.log(`Full restart completed (new PID: ${child.pid}, port: ${port})`);
|
|
86
|
+
}
|
|
87
|
+
else {
|
|
88
|
+
console.error('Failed to start new process');
|
|
89
|
+
process.exit(1);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
//# sourceMappingURL=restart.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"restart.js","sourceRoot":"","sources":["../../src/commands/restart.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"start.d.ts","sourceRoot":"","sources":["../../src/commands/start.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AAWxC,wBAAgB,aAAa,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAuBpD"}
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import { spawn } from 'node:child_process';
|
|
2
|
+
import { openSync } from 'node:fs';
|
|
3
|
+
import { fileURLToPath } from 'node:url';
|
|
4
|
+
import { resolve, dirname } from 'node:path';
|
|
5
|
+
import { loadConfig } from '../config-loader.js';
|
|
6
|
+
import { writePid, removePid, readPid, isProcessAlive } from '../pid.js';
|
|
7
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
8
|
+
const __dirname = dirname(__filename);
|
|
9
|
+
export function registerStart(program) {
|
|
10
|
+
program
|
|
11
|
+
.command('start')
|
|
12
|
+
.description('Start the Sena agent')
|
|
13
|
+
.option('-d, --daemon', 'run in background (daemon mode)')
|
|
14
|
+
.option('-c, --config <path>', 'path to sena.config.ts')
|
|
15
|
+
.action(async (opts) => {
|
|
16
|
+
ensureNoRunningProcess();
|
|
17
|
+
const configPath = opts.config ?? program.opts().config;
|
|
18
|
+
const { port, configPath: resolvedConfigPath, config } = await loadConfig(configPath);
|
|
19
|
+
// Set SENA_CONFIG_PATH so forked workers can find the config
|
|
20
|
+
process.env.SENA_CONFIG_PATH = resolvedConfigPath;
|
|
21
|
+
const agentName = config.name ?? 'default';
|
|
22
|
+
if (opts.daemon) {
|
|
23
|
+
await startDaemon(resolvedConfigPath, port, agentName);
|
|
24
|
+
}
|
|
25
|
+
else {
|
|
26
|
+
await startForeground(resolvedConfigPath, port, agentName);
|
|
27
|
+
}
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
function ensureNoRunningProcess() {
|
|
31
|
+
const pid = readPid();
|
|
32
|
+
if (pid === null) {
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
35
|
+
if (!isProcessAlive(pid)) {
|
|
36
|
+
removePid();
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
console.error(`Sena agent is already running (PID: ${pid})`);
|
|
40
|
+
process.exit(1);
|
|
41
|
+
}
|
|
42
|
+
async function startDaemon(configPath, port, agentName) {
|
|
43
|
+
const cliPath = resolve(__dirname, '..', 'cli.js');
|
|
44
|
+
const logPath = resolve(process.cwd(), 'sena.log');
|
|
45
|
+
const logFd = openSync(logPath, 'a');
|
|
46
|
+
// Build args: start (without -d), preserving config path if provided
|
|
47
|
+
const args = ['start'];
|
|
48
|
+
if (process.env.SENA_CONFIG_PATH) {
|
|
49
|
+
args.push('-c', process.env.SENA_CONFIG_PATH);
|
|
50
|
+
}
|
|
51
|
+
const child = spawn(process.execPath, [cliPath, ...args], {
|
|
52
|
+
detached: true,
|
|
53
|
+
stdio: ['ignore', logFd, logFd],
|
|
54
|
+
env: { ...process.env, SENA_CONFIG_PATH: configPath },
|
|
55
|
+
});
|
|
56
|
+
child.unref();
|
|
57
|
+
if (child.pid) {
|
|
58
|
+
console.log(`Sena agent '${agentName}' started in background (PID: ${child.pid}, port: ${port})`);
|
|
59
|
+
}
|
|
60
|
+
else {
|
|
61
|
+
console.error('Failed to start daemon process');
|
|
62
|
+
process.exit(1);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
async function startForeground(configPath, port, agentName) {
|
|
66
|
+
const { createOrchestrator } = await import('@sena-ai/core');
|
|
67
|
+
// Worker entry path (relative to dist/)
|
|
68
|
+
const workerEntryPath = resolve(__dirname, '..', 'worker-entry.js');
|
|
69
|
+
const orchestrator = createOrchestrator({
|
|
70
|
+
port,
|
|
71
|
+
workerScript: workerEntryPath,
|
|
72
|
+
});
|
|
73
|
+
await orchestrator.start();
|
|
74
|
+
writePid(process.pid);
|
|
75
|
+
console.log(`Sena agent '${agentName}' started on port ${port}`);
|
|
76
|
+
// SIGUSR2 → graceful worker restart
|
|
77
|
+
process.on('SIGUSR2', () => {
|
|
78
|
+
console.log('Received SIGUSR2, restarting workers...');
|
|
79
|
+
void orchestrator.restart();
|
|
80
|
+
});
|
|
81
|
+
// SIGINT/SIGTERM → graceful shutdown
|
|
82
|
+
const shutdown = async () => {
|
|
83
|
+
console.log('Shutting down...');
|
|
84
|
+
await orchestrator.stop();
|
|
85
|
+
removePid();
|
|
86
|
+
process.exit(0);
|
|
87
|
+
};
|
|
88
|
+
process.on('SIGINT', () => void shutdown());
|
|
89
|
+
process.on('SIGTERM', () => void shutdown());
|
|
90
|
+
}
|
|
91
|
+
//# sourceMappingURL=start.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"start.js","sourceRoot":"","sources":["../../src/commands/start.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"status.d.ts","sourceRoot":"","sources":["../../src/commands/status.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AAKxC,wBAAgB,cAAc,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAkCrD"}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { request } from 'node:http';
|
|
2
|
+
import { readPid, isProcessAlive, removePid } from '../pid.js';
|
|
3
|
+
import { loadConfig } from '../config-loader.js';
|
|
4
|
+
export function registerStatus(program) {
|
|
5
|
+
program
|
|
6
|
+
.command('status')
|
|
7
|
+
.description('Show the status of the Sena agent')
|
|
8
|
+
.option('-c, --config <path>', 'path to sena.config.ts')
|
|
9
|
+
.action(async (opts) => {
|
|
10
|
+
const pid = readPid();
|
|
11
|
+
if (pid === null || !isProcessAlive(pid)) {
|
|
12
|
+
if (pid !== null) {
|
|
13
|
+
removePid();
|
|
14
|
+
}
|
|
15
|
+
console.log('No running sena agent found');
|
|
16
|
+
return;
|
|
17
|
+
}
|
|
18
|
+
// Try to determine port from config / .env
|
|
19
|
+
let port;
|
|
20
|
+
try {
|
|
21
|
+
const configPath = opts.config ?? program.opts().config;
|
|
22
|
+
const result = await loadConfig(configPath);
|
|
23
|
+
port = result.port;
|
|
24
|
+
}
|
|
25
|
+
catch {
|
|
26
|
+
port = parseInt(process.env.SENA_PORT || '3100', 10);
|
|
27
|
+
}
|
|
28
|
+
// Health check
|
|
29
|
+
const healthy = await checkHealth(port);
|
|
30
|
+
if (healthy) {
|
|
31
|
+
console.log(`Sena agent running (PID: ${pid}, port: ${port})`);
|
|
32
|
+
}
|
|
33
|
+
else {
|
|
34
|
+
console.log(`Sena agent process alive (PID: ${pid}) but not responding on port ${port}`);
|
|
35
|
+
}
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
function checkHealth(port) {
|
|
39
|
+
return new Promise((resolve) => {
|
|
40
|
+
const req = request({
|
|
41
|
+
hostname: '127.0.0.1',
|
|
42
|
+
port,
|
|
43
|
+
path: '/health',
|
|
44
|
+
method: 'GET',
|
|
45
|
+
timeout: 3000,
|
|
46
|
+
}, (res) => {
|
|
47
|
+
resolve(res.statusCode === 200);
|
|
48
|
+
res.resume();
|
|
49
|
+
});
|
|
50
|
+
req.on('error', () => resolve(false));
|
|
51
|
+
req.on('timeout', () => {
|
|
52
|
+
req.destroy();
|
|
53
|
+
resolve(false);
|
|
54
|
+
});
|
|
55
|
+
req.end();
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
//# sourceMappingURL=status.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"status.js","sourceRoot":"","sources":["../../src/commands/status.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AACnC,OAAO,EAAE,OAAO,EAAE,cAAc,EAAE,SAAS,EAAE,MAAM,WAAW,CAAA;AAC9D,OAAO,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAA;AAEhD,MAAM,UAAU,cAAc,CAAC,OAAgB;IAC7C,OAAO;SACJ,OAAO,CAAC,QAAQ,CAAC;SACjB,WAAW,CAAC,mCAAmC,CAAC;SAChD,MAAM,CAAC,qBAAqB,EAAE,wBAAwB,CAAC;SACvD,MAAM,CAAC,KAAK,EAAE,IAAyB,EAAE,EAAE;QAC1C,MAAM,GAAG,GAAG,OAAO,EAAE,CAAA;QAErB,IAAI,GAAG,KAAK,IAAI,IAAI,CAAC,cAAc,CAAC,GAAG,CAAC,EAAE,CAAC;YACzC,IAAI,GAAG,KAAK,IAAI,EAAE,CAAC;gBACjB,SAAS,EAAE,CAAA;YACb,CAAC;YACD,OAAO,CAAC,GAAG,CAAC,6BAA6B,CAAC,CAAA;YAC1C,OAAM;QACR,CAAC;QAED,2CAA2C;QAC3C,IAAI,IAAY,CAAA;QAChB,IAAI,CAAC;YACH,MAAM,UAAU,GAAG,IAAI,CAAC,MAAM,IAAI,OAAO,CAAC,IAAI,EAAE,CAAC,MAA4B,CAAA;YAC7E,MAAM,MAAM,GAAG,MAAM,UAAU,CAAC,UAAU,CAAC,CAAA;YAC3C,IAAI,GAAG,MAAM,CAAC,IAAI,CAAA;QACpB,CAAC;QAAC,MAAM,CAAC;YACP,IAAI,GAAG,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,SAAS,IAAI,MAAM,EAAE,EAAE,CAAC,CAAA;QACtD,CAAC;QAED,eAAe;QACf,MAAM,OAAO,GAAG,MAAM,WAAW,CAAC,IAAI,CAAC,CAAA;QACvC,IAAI,OAAO,EAAE,CAAC;YACZ,OAAO,CAAC,GAAG,CAAC,4BAA4B,GAAG,WAAW,IAAI,GAAG,CAAC,CAAA;QAChE,CAAC;aAAM,CAAC;YACN,OAAO,CAAC,GAAG,CAAC,kCAAkC,GAAG,gCAAgC,IAAI,EAAE,CAAC,CAAA;QAC1F,CAAC;IACH,CAAC,CAAC,CAAA;AACN,CAAC;AAED,SAAS,WAAW,CAAC,IAAY;IAC/B,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE;QAC7B,MAAM,GAAG,GAAG,OAAO,CACjB;YACE,QAAQ,EAAE,WAAW;YACrB,IAAI;YACJ,IAAI,EAAE,SAAS;YACf,MAAM,EAAE,KAAK;YACb,OAAO,EAAE,IAAI;SACd,EACD,CAAC,GAAG,EAAE,EAAE;YACN,OAAO,CAAC,GAAG,CAAC,UAAU,KAAK,GAAG,CAAC,CAAA;YAC/B,GAAG,CAAC,MAAM,EAAE,CAAA;QACd,CAAC,CACF,CAAA;QAED,GAAG,CAAC,EAAE,CAAC,OAAO,EAAE,GAAG,EAAE,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAA;QACrC,GAAG,CAAC,EAAE,CAAC,SAAS,EAAE,GAAG,EAAE;YACrB,GAAG,CAAC,OAAO,EAAE,CAAA;YACb,OAAO,CAAC,KAAK,CAAC,CAAA;QAChB,CAAC,CAAC,CAAA;QAEF,GAAG,CAAC,GAAG,EAAE,CAAA;IACX,CAAC,CAAC,CAAA;AACJ,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"stop.d.ts","sourceRoot":"","sources":["../../src/commands/stop.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AAGxC,wBAAgB,YAAY,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAgDnD"}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { readPid, removePid, isProcessAlive } from '../pid.js';
|
|
2
|
+
export function registerStop(program) {
|
|
3
|
+
program
|
|
4
|
+
.command('stop')
|
|
5
|
+
.description('Stop the running Sena agent')
|
|
6
|
+
.action(async () => {
|
|
7
|
+
const pid = readPid();
|
|
8
|
+
if (pid === null) {
|
|
9
|
+
console.log('No running sena process found');
|
|
10
|
+
return;
|
|
11
|
+
}
|
|
12
|
+
if (!isProcessAlive(pid)) {
|
|
13
|
+
removePid();
|
|
14
|
+
console.log(`Process (PID: ${pid}) not running, cleaned up stale PID file`);
|
|
15
|
+
return;
|
|
16
|
+
}
|
|
17
|
+
// Send SIGTERM for graceful shutdown
|
|
18
|
+
process.kill(pid, 'SIGTERM');
|
|
19
|
+
console.log(`Sent SIGTERM to process ${pid}, waiting for shutdown...`);
|
|
20
|
+
// Wait up to 10 seconds
|
|
21
|
+
const maxWait = 10_000;
|
|
22
|
+
const interval = 100;
|
|
23
|
+
let waited = 0;
|
|
24
|
+
while (waited < maxWait) {
|
|
25
|
+
await new Promise((r) => setTimeout(r, interval));
|
|
26
|
+
waited += interval;
|
|
27
|
+
if (!isProcessAlive(pid)) {
|
|
28
|
+
removePid();
|
|
29
|
+
console.log('Sena agent stopped');
|
|
30
|
+
return;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
// Force kill if still alive
|
|
34
|
+
console.log('Process did not stop gracefully, sending SIGKILL...');
|
|
35
|
+
try {
|
|
36
|
+
process.kill(pid, 'SIGKILL');
|
|
37
|
+
}
|
|
38
|
+
catch {
|
|
39
|
+
// Process may have exited between check and kill
|
|
40
|
+
}
|
|
41
|
+
removePid();
|
|
42
|
+
console.log('Sena agent stopped (forced)');
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
//# sourceMappingURL=stop.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"stop.js","sourceRoot":"","sources":["../../src/commands/stop.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,OAAO,EAAE,SAAS,EAAE,cAAc,EAAE,MAAM,WAAW,CAAA;AAE9D,MAAM,UAAU,YAAY,CAAC,OAAgB;IAC3C,OAAO;SACJ,OAAO,CAAC,MAAM,CAAC;SACf,WAAW,CAAC,6BAA6B,CAAC;SAC1C,MAAM,CAAC,KAAK,IAAI,EAAE;QACjB,MAAM,GAAG,GAAG,OAAO,EAAE,CAAA;QAErB,IAAI,GAAG,KAAK,IAAI,EAAE,CAAC;YACjB,OAAO,CAAC,GAAG,CAAC,+BAA+B,CAAC,CAAA;YAC5C,OAAM;QACR,CAAC;QAED,IAAI,CAAC,cAAc,CAAC,GAAG,CAAC,EAAE,CAAC;YACzB,SAAS,EAAE,CAAA;YACX,OAAO,CAAC,GAAG,CAAC,iBAAiB,GAAG,0CAA0C,CAAC,CAAA;YAC3E,OAAM;QACR,CAAC;QAED,qCAAqC;QACrC,OAAO,CAAC,IAAI,CAAC,GAAG,EAAE,SAAS,CAAC,CAAA;QAC5B,OAAO,CAAC,GAAG,CAAC,2BAA2B,GAAG,2BAA2B,CAAC,CAAA;QAEtE,wBAAwB;QACxB,MAAM,OAAO,GAAG,MAAM,CAAA;QACtB,MAAM,QAAQ,GAAG,GAAG,CAAA;QACpB,IAAI,MAAM,GAAG,CAAC,CAAA;QAEd,OAAO,MAAM,GAAG,OAAO,EAAE,CAAC;YACxB,MAAM,IAAI,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,UAAU,CAAC,CAAC,EAAE,QAAQ,CAAC,CAAC,CAAA;YACjD,MAAM,IAAI,QAAQ,CAAA;YAClB,IAAI,CAAC,cAAc,CAAC,GAAG,CAAC,EAAE,CAAC;gBACzB,SAAS,EAAE,CAAA;gBACX,OAAO,CAAC,GAAG,CAAC,oBAAoB,CAAC,CAAA;gBACjC,OAAM;YACR,CAAC;QACH,CAAC;QAED,4BAA4B;QAC5B,OAAO,CAAC,GAAG,CAAC,qDAAqD,CAAC,CAAA;QAClE,IAAI,CAAC;YACH,OAAO,CAAC,IAAI,CAAC,GAAG,EAAE,SAAS,CAAC,CAAA;QAC9B,CAAC;QAAC,MAAM,CAAC;YACP,iDAAiD;QACnD,CAAC;QAED,SAAS,EAAE,CAAA;QACX,OAAO,CAAC,GAAG,CAAC,6BAA6B,CAAC,CAAA;IAC5C,CAAC,CAAC,CAAA;AACN,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config-loader.d.ts","sourceRoot":"","sources":["../src/config-loader.ts"],"names":[],"mappings":"AAGA,MAAM,MAAM,gBAAgB,GAAG;IAC7B,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;IAC/B,IAAI,EAAE,MAAM,CAAA;IACZ,UAAU,EAAE,MAAM,CAAA;CACnB,CAAA;AAyBD,wBAAsB,UAAU,CAAC,UAAU,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,gBAAgB,CAAC,CAoB/E"}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { resolve } from 'node:path';
|
|
2
|
+
import dotenv from 'dotenv';
|
|
3
|
+
function unwrapConfigModule(mod) {
|
|
4
|
+
const first = (mod.default ?? mod);
|
|
5
|
+
return (first.default ?? first);
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* Dynamically import a TypeScript file using tsx's tsImport API.
|
|
9
|
+
* Falls back to plain dynamic import for non-TS files or if tsx is unavailable.
|
|
10
|
+
*/
|
|
11
|
+
async function importTs(filePath) {
|
|
12
|
+
if (filePath.endsWith('.ts') || filePath.endsWith('.tsx')) {
|
|
13
|
+
try {
|
|
14
|
+
const { tsImport } = await import('tsx/esm/api');
|
|
15
|
+
const mod = await tsImport(filePath, import.meta.url);
|
|
16
|
+
return unwrapConfigModule(mod);
|
|
17
|
+
}
|
|
18
|
+
catch {
|
|
19
|
+
// Fall back to plain import (works if tsx is active via --import flag)
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
const mod = await import(filePath);
|
|
23
|
+
return unwrapConfigModule(mod);
|
|
24
|
+
}
|
|
25
|
+
export async function loadConfig(configPath) {
|
|
26
|
+
const cwd = process.cwd();
|
|
27
|
+
// 1. Load .env
|
|
28
|
+
dotenv.config({ path: resolve(cwd, '.env'), override: true });
|
|
29
|
+
// 2. Resolve config path
|
|
30
|
+
const resolvedConfigPath = configPath
|
|
31
|
+
? resolve(cwd, configPath)
|
|
32
|
+
: resolve(cwd, 'sena.config.ts');
|
|
33
|
+
// 3. Dynamic import of user config (using tsx tsImport for .ts files)
|
|
34
|
+
const config = await importTs(resolvedConfigPath);
|
|
35
|
+
// 4. Resolve port
|
|
36
|
+
const orchestrator = config.orchestrator;
|
|
37
|
+
const port = orchestrator?.port
|
|
38
|
+
?? parseInt(process.env.SENA_PORT || '3100', 10);
|
|
39
|
+
return { config, port, configPath: resolvedConfigPath };
|
|
40
|
+
}
|
|
41
|
+
//# sourceMappingURL=config-loader.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config-loader.js","sourceRoot":"","sources":["../src/config-loader.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AACnC,OAAO,MAAM,MAAM,QAAQ,CAAA;AAQ3B,SAAS,kBAAkB,CAAC,GAA4B;IACtD,MAAM,KAAK,GAAG,CAAC,GAAG,CAAC,OAAO,IAAI,GAAG,CAA4B,CAAA;IAC7D,OAAO,CAAC,KAAK,CAAC,OAAO,IAAI,KAAK,CAA4B,CAAA;AAC5D,CAAC;AAED;;;GAGG;AACH,KAAK,UAAU,QAAQ,CAAC,QAAgB;IACtC,IAAI,QAAQ,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,QAAQ,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC;QAC1D,IAAI,CAAC;YACH,MAAM,EAAE,QAAQ,EAAE,GAAG,MAAM,MAAM,CAAC,aAAa,CAAC,CAAA;YAChD,MAAM,GAAG,GAAG,MAAM,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC,IAAI,CAAC,GAAG,CAA4B,CAAA;YAChF,OAAO,kBAAkB,CAAC,GAAG,CAAC,CAAA;QAChC,CAAC;QAAC,MAAM,CAAC;YACP,uEAAuE;QACzE,CAAC;IACH,CAAC;IACD,MAAM,GAAG,GAAG,MAAM,MAAM,CAAC,QAAQ,CAA4B,CAAA;IAC7D,OAAO,kBAAkB,CAAC,GAAG,CAAC,CAAA;AAChC,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,UAAU,CAAC,UAAmB;IAClD,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,EAAE,CAAA;IAEzB,eAAe;IACf,MAAM,CAAC,MAAM,CAAC,EAAE,IAAI,EAAE,OAAO,CAAC,GAAG,EAAE,MAAM,CAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAA;IAE7D,yBAAyB;IACzB,MAAM,kBAAkB,GAAG,UAAU;QACnC,CAAC,CAAC,OAAO,CAAC,GAAG,EAAE,UAAU,CAAC;QAC1B,CAAC,CAAC,OAAO,CAAC,GAAG,EAAE,gBAAgB,CAAC,CAAA;IAElC,sEAAsE;IACtE,MAAM,MAAM,GAAG,MAAM,QAAQ,CAAC,kBAAkB,CAAC,CAAA;IAEjD,kBAAkB;IAClB,MAAM,YAAY,GAAG,MAAM,CAAC,YAA6C,CAAA;IACzE,MAAM,IAAI,GAAG,YAAY,EAAE,IAAI;WAC1B,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,SAAS,IAAI,MAAM,EAAE,EAAE,CAAC,CAAA;IAElD,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,UAAU,EAAE,kBAAkB,EAAE,CAAA;AACzD,CAAC"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAA;AAC/C,YAAY,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAA"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAA"}
|
package/dist/pid.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pid.d.ts","sourceRoot":"","sources":["../src/pid.ts"],"names":[],"mappings":"AAKA,wBAAgB,QAAQ,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAE1C;AAED,wBAAgB,OAAO,IAAI,MAAM,GAAG,IAAI,CAQvC;AAED,wBAAgB,SAAS,IAAI,IAAI,CAMhC;AAED,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAOnD"}
|
package/dist/pid.js
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { resolve } from 'node:path';
|
|
2
|
+
import { writeFileSync, readFileSync, unlinkSync } from 'node:fs';
|
|
3
|
+
const PID_FILE = () => resolve(process.cwd(), '.sena.pid');
|
|
4
|
+
export function writePid(pid) {
|
|
5
|
+
writeFileSync(PID_FILE(), String(pid), 'utf-8');
|
|
6
|
+
}
|
|
7
|
+
export function readPid() {
|
|
8
|
+
try {
|
|
9
|
+
const content = readFileSync(PID_FILE(), 'utf-8').trim();
|
|
10
|
+
const pid = parseInt(content, 10);
|
|
11
|
+
return Number.isNaN(pid) ? null : pid;
|
|
12
|
+
}
|
|
13
|
+
catch {
|
|
14
|
+
return null;
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
export function removePid() {
|
|
18
|
+
try {
|
|
19
|
+
unlinkSync(PID_FILE());
|
|
20
|
+
}
|
|
21
|
+
catch {
|
|
22
|
+
// Ignore if file doesn't exist
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
export function isProcessAlive(pid) {
|
|
26
|
+
try {
|
|
27
|
+
process.kill(pid, 0);
|
|
28
|
+
return true;
|
|
29
|
+
}
|
|
30
|
+
catch {
|
|
31
|
+
return false;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
//# sourceMappingURL=pid.js.map
|
package/dist/pid.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pid.js","sourceRoot":"","sources":["../src/pid.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AACnC,OAAO,EAAE,aAAa,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,SAAS,CAAA;AAEjE,MAAM,QAAQ,GAAG,GAAG,EAAE,CAAC,OAAO,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,WAAW,CAAC,CAAA;AAE1D,MAAM,UAAU,QAAQ,CAAC,GAAW;IAClC,aAAa,CAAC,QAAQ,EAAE,EAAE,MAAM,CAAC,GAAG,CAAC,EAAE,OAAO,CAAC,CAAA;AACjD,CAAC;AAED,MAAM,UAAU,OAAO;IACrB,IAAI,CAAC;QACH,MAAM,OAAO,GAAG,YAAY,CAAC,QAAQ,EAAE,EAAE,OAAO,CAAC,CAAC,IAAI,EAAE,CAAA;QACxD,MAAM,GAAG,GAAG,QAAQ,CAAC,OAAO,EAAE,EAAE,CAAC,CAAA;QACjC,OAAO,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,CAAA;IACvC,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAA;IACb,CAAC;AACH,CAAC;AAED,MAAM,UAAU,SAAS;IACvB,IAAI,CAAC;QACH,UAAU,CAAC,QAAQ,EAAE,CAAC,CAAA;IACxB,CAAC;IAAC,MAAM,CAAC;QACP,+BAA+B;IACjC,CAAC;AACH,CAAC;AAED,MAAM,UAAU,cAAc,CAAC,GAAW;IACxC,IAAI,CAAC;QACH,OAAO,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC,CAAA;QACpB,OAAO,IAAI,CAAA;IACb,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAA;IACd,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"worker-entry.d.ts","sourceRoot":"","sources":["../src/worker-entry.ts"],"names":[],"mappings":"AAAA,OAAO,eAAe,CAAA"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import 'dotenv/config';
|
|
2
|
+
import { createWorker } from '@sena-ai/core';
|
|
3
|
+
const configPath = process.env.SENA_CONFIG_PATH;
|
|
4
|
+
if (!configPath) {
|
|
5
|
+
console.error('SENA_CONFIG_PATH environment variable is required');
|
|
6
|
+
process.exit(1);
|
|
7
|
+
}
|
|
8
|
+
// Use tsx tsImport for .ts config files (plain import won't work from compiled .js)
|
|
9
|
+
let config;
|
|
10
|
+
if (configPath.endsWith('.ts') || configPath.endsWith('.tsx')) {
|
|
11
|
+
const { tsImport } = await import('tsx/esm/api');
|
|
12
|
+
const mod = await tsImport(configPath, import.meta.url);
|
|
13
|
+
config = mod.default;
|
|
14
|
+
}
|
|
15
|
+
else {
|
|
16
|
+
const mod = await import(configPath);
|
|
17
|
+
config = mod.default;
|
|
18
|
+
}
|
|
19
|
+
const port = parseInt(process.env.SENA_WORKER_PORT || '0', 10);
|
|
20
|
+
const worker = createWorker({ config, port });
|
|
21
|
+
worker.start();
|
|
22
|
+
//# sourceMappingURL=worker-entry.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"worker-entry.js","sourceRoot":"","sources":["../src/worker-entry.ts"],"names":[],"mappings":"AAAA,OAAO,eAAe,CAAA;AACtB,OAAO,EAAE,YAAY,EAAE,MAAM,eAAe,CAAA;AAE5C,MAAM,UAAU,GAAG,OAAO,CAAC,GAAG,CAAC,gBAAgB,CAAA;AAC/C,IAAI,CAAC,UAAU,EAAE,CAAC;IAChB,OAAO,CAAC,KAAK,CAAC,mDAAmD,CAAC,CAAA;IAClE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;AACjB,CAAC;AAED,oFAAoF;AACpF,IAAI,MAAoD,CAAA;AACxD,IAAI,UAAU,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,UAAU,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC;IAC9D,MAAM,EAAE,QAAQ,EAAE,GAAG,MAAM,MAAM,CAAC,aAAa,CAAC,CAAA;IAChD,MAAM,GAAG,GAAG,MAAM,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC,IAAI,CAAC,GAAG,CAA+B,CAAA;IACrF,MAAM,GAAG,GAAG,CAAC,OAAO,CAAA;AACtB,CAAC;KAAM,CAAC;IACN,MAAM,GAAG,GAAG,MAAM,MAAM,CAAC,UAAU,CAA+B,CAAA;IAClE,MAAM,GAAG,GAAG,CAAC,OAAO,CAAA;AACtB,CAAC;AAED,MAAM,IAAI,GAAG,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,gBAAgB,IAAI,GAAG,EAAE,EAAE,CAAC,CAAA;AAE9D,MAAM,MAAM,GAAG,YAAY,CAAC,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,CAAA;AAC7C,MAAM,CAAC,KAAK,EAAE,CAAA"}
|
package/package.json
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@sena-ai/cli",
|
|
3
|
+
"version": "0.0.15",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"bin": {
|
|
6
|
+
"sena": "./dist/cli.js"
|
|
7
|
+
},
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"types": "./dist/index.d.ts",
|
|
11
|
+
"import": "./dist/index.js",
|
|
12
|
+
"default": "./dist/index.js"
|
|
13
|
+
}
|
|
14
|
+
},
|
|
15
|
+
"files": [
|
|
16
|
+
"dist"
|
|
17
|
+
],
|
|
18
|
+
"scripts": {
|
|
19
|
+
"build": "tsc -b"
|
|
20
|
+
},
|
|
21
|
+
"dependencies": {
|
|
22
|
+
"tsx": "^4.21.0",
|
|
23
|
+
"commander": "^13",
|
|
24
|
+
"dotenv": "^16.6",
|
|
25
|
+
"@sena-ai/core": "workspace:*"
|
|
26
|
+
},
|
|
27
|
+
"devDependencies": {
|
|
28
|
+
"@types/node": "^25.5.0",
|
|
29
|
+
"typescript": "^5.8.0"
|
|
30
|
+
}
|
|
31
|
+
}
|