shennian 0.2.27 → 0.2.29
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 +2 -0
- package/dist/src/agents/command-spec.js +2 -3
- package/dist/src/agents/model-registry/discovery.js +10 -9
- package/dist/src/agents/openclaw.js +3 -2
- package/dist/src/commands/daemon.d.ts +2 -0
- package/dist/src/commands/daemon.js +17 -1
- package/dist/src/index.js +8 -4
- package/dist/src/session/manager.d.ts +0 -1
- package/dist/src/session/manager.js +2 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -20,10 +20,12 @@
|
|
|
20
20
|
| `shennian status` | 查看后台服务状态 |
|
|
21
21
|
| `shennian logs -n 100` | 查看最近日志 |
|
|
22
22
|
| `shennian config` | 查看本地配置 |
|
|
23
|
+
| `shennian config set server cn\|global` | 切换国内 / 海外中继节点 |
|
|
23
24
|
| `shennian agent add/list/remove` | 管理自定义 Agent |
|
|
24
25
|
| `shennian upgrade` | 升级 CLI |
|
|
25
26
|
|
|
26
27
|
`start`、`stop`、`status` 可选加 `--json`。`logs` 输出日志文本,不支持 `--json`。
|
|
28
|
+
切换节点后运行 `shennian stop && shennian start` 让后台服务重新连接。
|
|
27
29
|
|
|
28
30
|
## 开发
|
|
29
31
|
|
|
@@ -16,9 +16,8 @@ const BUILTIN_COMMANDS = {
|
|
|
16
16
|
{ command: 'agent', args: [], display: 'agent' },
|
|
17
17
|
{ command: 'cursor', args: ['agent'], display: 'cursor agent' },
|
|
18
18
|
],
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
],
|
|
19
|
+
// OpenClaw support is intentionally disabled.
|
|
20
|
+
openclaw: [],
|
|
22
21
|
opencode: [
|
|
23
22
|
{ command: 'opencode', args: [], display: 'opencode' },
|
|
24
23
|
],
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
// @test src/__tests__/model-switching.test.ts
|
|
3
3
|
import { createInterface } from 'node:readline';
|
|
4
4
|
import { resolveBuiltinCommand, spawnResolvedCommand } from '../command-spec.js';
|
|
5
|
-
import { fallbackClaudeAliasModels, fallbackGeminiModels, parseCodexAppServerModels, parseCursorModels, parseOpenCodeModels,
|
|
5
|
+
import { fallbackClaudeAliasModels, fallbackGeminiModels, parseCodexAppServerModels, parseCursorModels, parseOpenCodeModels, } from './parsers.js';
|
|
6
6
|
import { runResolvedCommand } from './runner.js';
|
|
7
7
|
import { DISCOVERY_WORKDIR } from './types.js';
|
|
8
8
|
function sendAppServerRpc(proc, pending, id, method, params, timeoutMs) {
|
|
@@ -90,13 +90,13 @@ async function discoverCursorModels() {
|
|
|
90
90
|
const result = await runResolvedCommand(spec, ['--list-models']);
|
|
91
91
|
return parseCursorModels(result.stdout);
|
|
92
92
|
}
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
}
|
|
93
|
+
// OpenClaw support is intentionally disabled.
|
|
94
|
+
// async function discoverOpenClawModels(): Promise<ModelInfo[]> {
|
|
95
|
+
// const spec = resolveBuiltinCommand('openclaw')
|
|
96
|
+
// if (!spec) return []
|
|
97
|
+
// const result = await runResolvedCommand(spec, ['models', 'list', '--json'])
|
|
98
|
+
// return parseOpenClawModels(result.stdout)
|
|
99
|
+
// }
|
|
100
100
|
async function discoverOpenCodeModels() {
|
|
101
101
|
const spec = resolveBuiltinCommand('opencode');
|
|
102
102
|
if (!spec)
|
|
@@ -160,7 +160,8 @@ async function discoverBuiltinModels(type, context) {
|
|
|
160
160
|
case 'cursor':
|
|
161
161
|
return discoverCursorModels();
|
|
162
162
|
case 'openclaw':
|
|
163
|
-
|
|
163
|
+
// OpenClaw support is intentionally disabled.
|
|
164
|
+
return [];
|
|
164
165
|
case 'opencode':
|
|
165
166
|
return discoverOpenCodeModels();
|
|
166
167
|
case 'pi':
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { randomUUID } from 'node:crypto';
|
|
2
|
-
import { AgentAdapter
|
|
2
|
+
import { AgentAdapter } from './adapter.js';
|
|
3
3
|
import { resolveBuiltinCommand, spawnResolvedCommand } from './command-spec.js';
|
|
4
4
|
/** Best-effort parse of `openclaw agent --json` stdout; shape may vary by version. */
|
|
5
5
|
function extractResponseText(parsed) {
|
|
@@ -270,4 +270,5 @@ export class OpenClawAdapter extends AgentAdapter {
|
|
|
270
270
|
});
|
|
271
271
|
}
|
|
272
272
|
}
|
|
273
|
-
|
|
273
|
+
// OpenClaw support is intentionally disabled.
|
|
274
|
+
// registerAgent('openclaw', () => new OpenClawAdapter())
|
|
@@ -6,7 +6,7 @@ import path from 'node:path';
|
|
|
6
6
|
import os from 'node:os';
|
|
7
7
|
import { execSync, spawn } from 'node:child_process';
|
|
8
8
|
import { fileURLToPath } from 'node:url';
|
|
9
|
-
import { getShennianDir, resolveShennianPath } from '../config/index.js';
|
|
9
|
+
import { getShennianDir, loadConfig, resolveShennianPath, saveConfig } from '../config/index.js';
|
|
10
10
|
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
11
11
|
const SHENNIAN_DIR = getShennianDir();
|
|
12
12
|
const PID_FILE = resolveShennianPath('daemon.pid');
|
|
@@ -156,6 +156,7 @@ export function getDaemonStatus(opts = {}) {
|
|
|
156
156
|
const pid = readPid();
|
|
157
157
|
const running = pid !== null && isRunning(pid);
|
|
158
158
|
const stale = pid !== null && !running;
|
|
159
|
+
const config = loadConfig();
|
|
159
160
|
if (stale && opts.cleanupStale) {
|
|
160
161
|
try {
|
|
161
162
|
fs.unlinkSync(PID_FILE);
|
|
@@ -174,11 +175,21 @@ export function getDaemonStatus(opts = {}) {
|
|
|
174
175
|
shennianDir: SHENNIAN_DIR,
|
|
175
176
|
pidFile: PID_FILE,
|
|
176
177
|
logFile: LOG_FILE,
|
|
178
|
+
...(config.machineId ? { machineId: config.machineId } : {}),
|
|
179
|
+
...(config.serverUrl ? { serverUrl: config.serverUrl } : {}),
|
|
177
180
|
};
|
|
178
181
|
}
|
|
179
182
|
function printJson(value) {
|
|
180
183
|
process.stdout.write(`${JSON.stringify(value, null, 2)}\n`);
|
|
181
184
|
}
|
|
185
|
+
function persistServerUrlOverride(serverUrl) {
|
|
186
|
+
const normalized = serverUrl?.trim();
|
|
187
|
+
if (!normalized)
|
|
188
|
+
return;
|
|
189
|
+
const config = loadConfig();
|
|
190
|
+
config.serverUrl = normalized;
|
|
191
|
+
saveConfig(config);
|
|
192
|
+
}
|
|
182
193
|
// ─── Service definitions ─────────────────────────────────────────────────────
|
|
183
194
|
const LAUNCHD_LABEL = 'com.shennian.agent';
|
|
184
195
|
const LAUNCHD_PLIST = path.join(os.homedir(), 'Library/LaunchAgents', `${LAUNCHD_LABEL}.plist`);
|
|
@@ -639,6 +650,7 @@ async function stopDaemonProcessAndWait(timeoutMs = 5000) {
|
|
|
639
650
|
return result;
|
|
640
651
|
}
|
|
641
652
|
function enableRemoteAccess(opts = {}) {
|
|
653
|
+
persistServerUrlOverride(opts.api);
|
|
642
654
|
try {
|
|
643
655
|
fs.unlinkSync(REMOTE_ACCESS_DISABLED_FILE);
|
|
644
656
|
}
|
|
@@ -726,6 +738,7 @@ async function waitForPidExit(pid, timeoutMs = 5000) {
|
|
|
726
738
|
return !isRunning(pid);
|
|
727
739
|
}
|
|
728
740
|
async function daemonRestart(opts = {}) {
|
|
741
|
+
persistServerUrlOverride(opts.api);
|
|
729
742
|
const pid = readPid();
|
|
730
743
|
if (pid !== null && isRunning(pid)) {
|
|
731
744
|
try {
|
|
@@ -888,6 +901,7 @@ export function registerDaemonCommand(program) {
|
|
|
888
901
|
.command('start')
|
|
889
902
|
.description('Start the background service')
|
|
890
903
|
.option('--json', 'Print machine-readable status JSON')
|
|
904
|
+
.option('--api <url>', 'Server URL override')
|
|
891
905
|
.action((opts) => daemonStart(opts));
|
|
892
906
|
program
|
|
893
907
|
.command('stop')
|
|
@@ -913,6 +927,7 @@ export function registerDaemonCommand(program) {
|
|
|
913
927
|
.command('start')
|
|
914
928
|
.description('Start the background service')
|
|
915
929
|
.option('--json', 'Print machine-readable status JSON')
|
|
930
|
+
.option('--api <url>', 'Server URL override')
|
|
916
931
|
.action((opts) => {
|
|
917
932
|
warnDeprecated('start', opts.json);
|
|
918
933
|
daemonStart(opts);
|
|
@@ -929,6 +944,7 @@ export function registerDaemonCommand(program) {
|
|
|
929
944
|
.command('restart')
|
|
930
945
|
.description('Restart the background service')
|
|
931
946
|
.option('--json', 'Print machine-readable status JSON')
|
|
947
|
+
.option('--api <url>', 'Server URL override')
|
|
932
948
|
.action((opts) => {
|
|
933
949
|
warnDeprecated('stop && shennian start', opts.json);
|
|
934
950
|
daemonRestart(opts);
|
package/dist/src/index.js
CHANGED
|
@@ -89,16 +89,20 @@ program
|
|
|
89
89
|
catch {
|
|
90
90
|
// env.json may not exist yet
|
|
91
91
|
}
|
|
92
|
-
// Single-instance guard.
|
|
93
|
-
// need to take over from an older detached
|
|
92
|
+
// Single-instance guard. Service-manager starts are authoritative and may
|
|
93
|
+
// need to take over from an older detached process after app/daemon upgrades.
|
|
94
94
|
const pidFile = resolveShennianPath('daemon.pid');
|
|
95
95
|
try {
|
|
96
96
|
const oldPid = parseInt(fs.readFileSync(pidFile, 'utf-8').trim(), 10);
|
|
97
97
|
if (oldPid && oldPid !== process.pid) {
|
|
98
98
|
try {
|
|
99
99
|
process.kill(oldPid, 0);
|
|
100
|
-
|
|
101
|
-
|
|
100
|
+
const serviceManagedStart = Boolean(process.env.INVOCATION_ID ||
|
|
101
|
+
process.env.JOURNAL_STREAM ||
|
|
102
|
+
process.env.SHENNIAN_DESKTOP_CLI_SCRIPT ||
|
|
103
|
+
process.env.SHENNIAN_DESKTOP_CLI_BRIDGE);
|
|
104
|
+
if (serviceManagedStart) {
|
|
105
|
+
console.log(`[${new Date().toISOString()}] managed start taking over from existing daemon (PID ${oldPid})`);
|
|
102
106
|
process.kill(oldPid, 'SIGTERM');
|
|
103
107
|
const stopped = await waitForPidExit(oldPid);
|
|
104
108
|
if (!stopped) {
|
|
@@ -5,7 +5,6 @@ import '../agents/claude.js';
|
|
|
5
5
|
import '../agents/codex.js';
|
|
6
6
|
import '../agents/gemini.js';
|
|
7
7
|
import '../agents/cursor.js';
|
|
8
|
-
import '../agents/openclaw.js';
|
|
9
8
|
import '../agents/opencode.js';
|
|
10
9
|
import '../agents/pi.js';
|
|
11
10
|
export declare function resolveSessionWorkDir(input: string): string;
|
|
@@ -15,7 +15,8 @@ import '../agents/claude.js';
|
|
|
15
15
|
import '../agents/codex.js';
|
|
16
16
|
import '../agents/gemini.js';
|
|
17
17
|
import '../agents/cursor.js';
|
|
18
|
-
|
|
18
|
+
// OpenClaw support is intentionally disabled.
|
|
19
|
+
// import '../agents/openclaw.js'
|
|
19
20
|
import '../agents/opencode.js';
|
|
20
21
|
import '../agents/pi.js';
|
|
21
22
|
import { registerCustomAgent } from '../agents/custom.js';
|