fix(sf): expose daemon as sf-server
This commit is contained in:
parent
e5787794f3
commit
974d8e4b6d
9 changed files with 68 additions and 14 deletions
7
package-lock.json
generated
7
package-lock.json
generated
|
|
@ -61,7 +61,9 @@
|
|||
},
|
||||
"bin": {
|
||||
"sf": "dist/loader.js",
|
||||
"sf-cli": "dist/loader.js"
|
||||
"sf-cli": "dist/loader.js",
|
||||
"sf-daemon": "packages/daemon/dist/cli.js",
|
||||
"sf-server": "packages/daemon/dist/cli.js"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@biomejs/biome": "^2.4.13",
|
||||
|
|
@ -16327,7 +16329,8 @@
|
|||
"zod": "^3.24.0"
|
||||
},
|
||||
"bin": {
|
||||
"sf-daemon": "dist/cli.js"
|
||||
"sf-daemon": "dist/cli.js",
|
||||
"sf-server": "dist/cli.js"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "^24.12.0",
|
||||
|
|
|
|||
|
|
@ -18,7 +18,9 @@
|
|||
],
|
||||
"bin": {
|
||||
"sf": "dist/loader.js",
|
||||
"sf-cli": "dist/loader.js"
|
||||
"sf-cli": "dist/loader.js",
|
||||
"sf-daemon": "packages/daemon/dist/cli.js",
|
||||
"sf-server": "packages/daemon/dist/cli.js"
|
||||
},
|
||||
"files": [
|
||||
"dist",
|
||||
|
|
@ -49,7 +51,8 @@
|
|||
"build:rpc-client": "npm --workspace @singularity-forge/rpc-client run build",
|
||||
"build:pi": "npm run build:native-pkg && npm run build:pi-tui && npm run build:pi-ai && npm run build:pi-agent-core && npm run build:pi-coding-agent",
|
||||
"build:mcp-server": "npm --workspace @singularity-forge/mcp-server run build",
|
||||
"build:core": "npm run build:pi && npm run build:rpc-client && npm run build:mcp-server && npm run check:versioned-json && tsc && npm run copy-resources && npm run copy-themes && npm run copy-export-html",
|
||||
"build:daemon": "npm --workspace @singularity-forge/daemon run build",
|
||||
"build:core": "npm run build:pi && npm run build:rpc-client && npm run build:daemon && npm run build:mcp-server && npm run check:versioned-json && tsc && npm run copy-resources && npm run copy-themes && npm run copy-export-html",
|
||||
"build": "npm run build:core && node scripts/build-web-if-stale.cjs",
|
||||
"stage:web-host": "node scripts/stage-web-standalone.cjs",
|
||||
"build:web-host": "npm --prefix web run build && npm run stage:web-host",
|
||||
|
|
@ -78,6 +81,7 @@
|
|||
"build:native:dev": "node rust-engine/scripts/build.js --dev",
|
||||
"dev": "node scripts/dev.js",
|
||||
"sf": "node scripts/dev-cli.js",
|
||||
"sf:server": "node packages/daemon/dist/cli.js",
|
||||
"sf:web": "npm run build:pi && npm run copy-resources && node scripts/build-web-if-stale.cjs && node scripts/dev-cli.js --web",
|
||||
"sf:web:stop": "node scripts/dev-cli.js web stop",
|
||||
"sf:web:stop:all": "node scripts/dev-cli.js web stop all",
|
||||
|
|
|
|||
|
|
@ -21,11 +21,12 @@
|
|||
}
|
||||
},
|
||||
"bin": {
|
||||
"sf-daemon": "./dist/cli.js"
|
||||
"sf-daemon": "./dist/cli.js",
|
||||
"sf-server": "./dist/cli.js"
|
||||
},
|
||||
"scripts": {
|
||||
"build": "tsc",
|
||||
"test": "node --test dist/daemon.test.js"
|
||||
"test": "vitest run packages/daemon/src --root ../.. --config vitest.config.ts"
|
||||
},
|
||||
"dependencies": {
|
||||
"@anthropic-ai/sdk": "^0.92.0",
|
||||
|
|
|
|||
|
|
@ -6,7 +6,11 @@ import { Logger } from './logger.js';
|
|||
import { Daemon } from './daemon.js';
|
||||
import { install, uninstall, status } from './launchd.js';
|
||||
|
||||
const USAGE = `Usage: sf-daemon [options]
|
||||
const COMMAND_NAME = 'sf-server';
|
||||
|
||||
const USAGE = `Usage: sf-server [options]
|
||||
|
||||
Alias: sf-daemon
|
||||
|
||||
Options:
|
||||
--config <path> Path to YAML config file (default: ~/.sf/daemon.yaml)
|
||||
|
|
@ -46,27 +50,27 @@ async function main(): Promise<void> {
|
|||
scriptPath,
|
||||
configPath,
|
||||
});
|
||||
process.stdout.write('sf-daemon: launchd agent installed and loaded.\n');
|
||||
process.stdout.write(`${COMMAND_NAME}: launchd agent installed and loaded.\n`);
|
||||
process.exit(0);
|
||||
}
|
||||
|
||||
if (values.uninstall) {
|
||||
uninstall();
|
||||
process.stdout.write('sf-daemon: launchd agent uninstalled.\n');
|
||||
process.stdout.write(`${COMMAND_NAME}: launchd agent uninstalled.\n`);
|
||||
process.exit(0);
|
||||
}
|
||||
|
||||
if (values.status) {
|
||||
const result = status();
|
||||
if (!result.registered) {
|
||||
process.stdout.write('sf-daemon: not registered with launchd.\n');
|
||||
process.stdout.write(`${COMMAND_NAME}: not registered with launchd.\n`);
|
||||
} else if (result.pid != null) {
|
||||
process.stdout.write(
|
||||
`sf-daemon: running (PID ${result.pid}, last exit status: ${result.lastExitStatus ?? 'n/a'})\n`,
|
||||
`${COMMAND_NAME}: running (PID ${result.pid}, last exit status: ${result.lastExitStatus ?? 'n/a'})\n`,
|
||||
);
|
||||
} else {
|
||||
process.stdout.write(
|
||||
`sf-daemon: registered but not running (last exit status: ${result.lastExitStatus ?? 'n/a'})\n`,
|
||||
`${COMMAND_NAME}: registered but not running (last exit status: ${result.lastExitStatus ?? 'n/a'})\n`,
|
||||
);
|
||||
}
|
||||
process.exit(0);
|
||||
|
|
@ -89,6 +93,6 @@ async function main(): Promise<void> {
|
|||
|
||||
main().catch((err: unknown) => {
|
||||
const msg = err instanceof Error ? err.message : String(err);
|
||||
process.stderr.write(`sf-daemon: fatal: ${msg}\n`);
|
||||
process.stderr.write(`${COMMAND_NAME}: fatal: ${msg}\n`);
|
||||
process.exit(1);
|
||||
});
|
||||
|
|
|
|||
|
|
@ -550,7 +550,8 @@ describe('CLI integration', () => {
|
|||
[resolveCliPath()!, '--help'],
|
||||
{ encoding: 'utf-8', timeout: 5000 },
|
||||
);
|
||||
assert.ok(result.includes('Usage: sf-daemon'));
|
||||
assert.ok(result.includes('Usage: sf-server'));
|
||||
assert.ok(result.includes('Alias: sf-daemon'));
|
||||
assert.ok(result.includes('--config'));
|
||||
assert.ok(result.includes('--verbose'));
|
||||
});
|
||||
|
|
|
|||
|
|
@ -859,6 +859,17 @@ describe('SessionManager', () => {
|
|||
assert.equal(session.projectName, 'my-app');
|
||||
});
|
||||
|
||||
// ---- Default command starts autonomous mode ----
|
||||
|
||||
it('sends autonomous command when no command is provided', async () => {
|
||||
const { manager } = createManager();
|
||||
|
||||
await manager.startSession({ projectDir: '/tmp/default-autonomous' });
|
||||
const client = manager.lastClient!;
|
||||
|
||||
assert.ok(client.prompted.includes('/sf autonomous'));
|
||||
});
|
||||
|
||||
// ---- Custom command is sent instead of default ----
|
||||
|
||||
it('sends custom command when provided', async () => {
|
||||
|
|
|
|||
|
|
@ -98,6 +98,7 @@ if (require.main === module) {
|
|||
'pi-agent-core',
|
||||
'pi-coding-agent',
|
||||
'rpc-client',
|
||||
'daemon',
|
||||
'mcp-server',
|
||||
]
|
||||
|
||||
|
|
|
|||
|
|
@ -32,6 +32,7 @@ const packageDirs = [
|
|||
'pi-coding-agent',
|
||||
'pi-tui',
|
||||
'rpc-client',
|
||||
'daemon',
|
||||
'mcp-server',
|
||||
]
|
||||
|
||||
|
|
|
|||
|
|
@ -97,6 +97,7 @@ try {
|
|||
'dist/loader.js',
|
||||
'packages/pi-coding-agent/dist/index.js',
|
||||
'packages/rpc-client/dist/index.js',
|
||||
'packages/daemon/dist/cli.js',
|
||||
'packages/mcp-server/dist/cli.js',
|
||||
'scripts/link-workspace-packages.cjs',
|
||||
'dist/web/standalone/server.js',
|
||||
|
|
@ -151,6 +152,7 @@ try {
|
|||
const criticalPackages = [
|
||||
{ scope: '@singularity-forge', name: 'pi-coding-agent' },
|
||||
{ scope: '@singularity-forge', name: 'rpc-client' },
|
||||
{ scope: '@singularity-forge', name: 'daemon' },
|
||||
];
|
||||
let resolutionFailed = false;
|
||||
for (const pkg of criticalPackages) {
|
||||
|
|
@ -175,7 +177,13 @@ try {
|
|||
// --- Run the binary to confirm end-to-end resolution ---
|
||||
console.log('==> Running installed binary (sf -v)...');
|
||||
const loaderPath = join(installedRoot, 'dist', 'loader.js');
|
||||
const daemonCliPath = join(installedRoot, 'packages', 'daemon', 'dist', 'cli.js');
|
||||
const bundledWorkflowMcpCliPath = join(installedRoot, 'packages', 'mcp-server', 'dist', 'cli.js');
|
||||
if (!existsSync(daemonCliPath)) {
|
||||
console.log('ERROR: Bundled daemon CLI missing after install.');
|
||||
console.log(` Expected: ${daemonCliPath}`);
|
||||
process.exit(1);
|
||||
}
|
||||
if (!existsSync(bundledWorkflowMcpCliPath)) {
|
||||
console.log('ERROR: Bundled workflow MCP CLI missing after install.');
|
||||
console.log(` Expected: ${bundledWorkflowMcpCliPath}`);
|
||||
|
|
@ -201,6 +209,26 @@ try {
|
|||
process.exit(1);
|
||||
}
|
||||
|
||||
console.log('==> Running installed daemon binary (sf-server --help)...');
|
||||
try {
|
||||
const helpOutput = execFileSync(process.execPath, [daemonCliPath, '--help'], {
|
||||
cwd: installDir,
|
||||
encoding: 'utf8',
|
||||
stdio: ['pipe', 'pipe', 'pipe'],
|
||||
timeout: 15000,
|
||||
maxBuffer: DEFAULT_MAX_BUFFER,
|
||||
});
|
||||
if (!helpOutput.includes('Usage: sf-server')) {
|
||||
console.log('ERROR: sf-server --help returned unexpected output.');
|
||||
process.exit(1);
|
||||
}
|
||||
} catch (err) {
|
||||
console.log('ERROR: Running sf-server --help failed after install.');
|
||||
if (err.stdout) console.log(err.stdout);
|
||||
if (err.stderr) console.log(err.stderr);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
console.log('');
|
||||
console.log('Package is installable. Safe to publish.');
|
||||
process.exit(0);
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue