shennian 0.2.89 → 0.2.90

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.
Files changed (118) hide show
  1. package/dist/assets/wechat-channel/macos/manifest.json +13 -4
  2. package/dist/assets/wechat-channel/macos/shennian-wechat-channel-helper +0 -0
  3. package/dist/bin/shennian.js +1 -1
  4. package/dist/publish-build-manifest.json +548 -0
  5. package/dist/scripts/wechat-rpa-confirmation.mjs +5 -97
  6. package/dist/src/agent-env.js +4 -105
  7. package/dist/src/agents/adapter.js +1 -19
  8. package/dist/src/agents/claude.js +8 -305
  9. package/dist/src/agents/codex-control.js +2 -188
  10. package/dist/src/agents/codex-utils.js +7 -200
  11. package/dist/src/agents/codex.js +15 -916
  12. package/dist/src/agents/command-spec.js +2 -413
  13. package/dist/src/agents/config-status.js +1 -226
  14. package/dist/src/agents/cursor.js +1 -249
  15. package/dist/src/agents/custom.js +4 -271
  16. package/dist/src/agents/detect.js +1 -56
  17. package/dist/src/agents/external-channel-instructions.js +10 -94
  18. package/dist/src/agents/gemini.js +1 -173
  19. package/dist/src/agents/manager.js +13 -157
  20. package/dist/src/agents/model-registry/cache.js +1 -37
  21. package/dist/src/agents/model-registry/discovery.js +2 -187
  22. package/dist/src/agents/model-registry/parsers.js +4 -447
  23. package/dist/src/agents/model-registry/runner.js +1 -30
  24. package/dist/src/agents/model-registry/service.js +1 -78
  25. package/dist/src/agents/model-registry/types.js +1 -8
  26. package/dist/src/agents/model-registry.js +1 -18
  27. package/dist/src/agents/openclaw.js +2 -275
  28. package/dist/src/agents/opencode.js +1 -231
  29. package/dist/src/agents/pi-context.js +12 -217
  30. package/dist/src/agents/pi.js +14 -723
  31. package/dist/src/agents/platform-instructions.js +9 -54
  32. package/dist/src/channels/base.js +1 -3
  33. package/dist/src/channels/registry.js +1 -30
  34. package/dist/src/channels/reply-split.js +10 -89
  35. package/dist/src/channels/runtime.js +5 -564
  36. package/dist/src/channels/secret-registry.js +1 -46
  37. package/dist/src/channels/websocket.js +8 -378
  38. package/dist/src/channels/wechat-channel/anchor.js +1 -65
  39. package/dist/src/channels/wechat-channel/client.js +1 -96
  40. package/dist/src/channels/wechat-channel/cooldown.js +1 -38
  41. package/dist/src/channels/wechat-channel/fingerprint.js +1 -71
  42. package/dist/src/channels/wechat-channel/helper-assets.d.ts +10 -1
  43. package/dist/src/channels/wechat-channel/helper-assets.js +1 -68
  44. package/dist/src/channels/wechat-channel/helper-client.js +3 -149
  45. package/dist/src/channels/wechat-channel/helper-protocol.d.ts +1 -1
  46. package/dist/src/channels/wechat-channel/helper-protocol.js +1 -115
  47. package/dist/src/channels/wechat-channel/index.d.ts +1 -0
  48. package/dist/src/channels/wechat-channel/index.js +1 -19
  49. package/dist/src/channels/wechat-channel/ledger.js +1 -54
  50. package/dist/src/channels/wechat-channel/media-resolver.js +1 -181
  51. package/dist/src/channels/wechat-channel/message-key.js +1 -105
  52. package/dist/src/channels/wechat-channel/observer.js +1 -118
  53. package/dist/src/channels/wechat-channel/outbound-ledger.d.ts +3 -0
  54. package/dist/src/channels/wechat-channel/outbound-ledger.js +2 -112
  55. package/dist/src/channels/wechat-channel/outbound-sender.d.ts +26 -0
  56. package/dist/src/channels/wechat-channel/outbound-sender.js +1 -0
  57. package/dist/src/channels/wechat-channel/preflight.js +1 -48
  58. package/dist/src/channels/wechat-channel/runner.js +1 -84
  59. package/dist/src/channels/wechat-channel/runtime.js +1 -66
  60. package/dist/src/channels/wechat-channel/scheduler.d.ts +5 -0
  61. package/dist/src/channels/wechat-channel/scheduler.js +1 -152
  62. package/dist/src/channels/wechat-rpa/macos-flow.js +1 -96
  63. package/dist/src/channels/wechat-rpa/macos.js +6 -48
  64. package/dist/src/channels/wechat-rpa/normalizer.js +7 -127
  65. package/dist/src/channels/wechat-rpa.js +6 -1028
  66. package/dist/src/channels/wecom.js +4 -357
  67. package/dist/src/commands/agent.js +6 -131
  68. package/dist/src/commands/daemon-windows.js +8 -48
  69. package/dist/src/commands/daemon.js +19 -1013
  70. package/dist/src/commands/external-attachments.js +1 -51
  71. package/dist/src/commands/external.js +1 -137
  72. package/dist/src/commands/manager.js +2 -391
  73. package/dist/src/commands/pair-qr.js +1 -6
  74. package/dist/src/commands/pair.js +9 -287
  75. package/dist/src/commands/tools.js +1 -34
  76. package/dist/src/commands/upgrade.js +1 -198
  77. package/dist/src/config/index.js +1 -35
  78. package/dist/src/daemon-log.js +6 -58
  79. package/dist/src/env-path.js +1 -64
  80. package/dist/src/fs/boundary.js +1 -126
  81. package/dist/src/fs/handler.js +1 -130
  82. package/dist/src/fs/security.js +1 -32
  83. package/dist/src/fs/text-decoder.js +1 -110
  84. package/dist/src/index.js +2 -404
  85. package/dist/src/log-reporter.js +1 -16
  86. package/dist/src/manager/prompt.js +29 -34
  87. package/dist/src/manager/registry.js +2 -269
  88. package/dist/src/manager/runtime.js +19 -1007
  89. package/dist/src/native-fusion/config.js +1 -5
  90. package/dist/src/native-fusion/opencode-parser.js +3 -123
  91. package/dist/src/native-fusion/parser-common.js +8 -264
  92. package/dist/src/native-fusion/parsers.js +8 -729
  93. package/dist/src/native-fusion/service.js +2 -225
  94. package/dist/src/native-fusion/state.js +1 -22
  95. package/dist/src/native-fusion/types.js +1 -1
  96. package/dist/src/region.js +1 -88
  97. package/dist/src/relay/client.js +1 -343
  98. package/dist/src/session/archive-zip.js +1 -220
  99. package/dist/src/session/handlers/agent-config.js +1 -150
  100. package/dist/src/session/handlers/agents.js +1 -55
  101. package/dist/src/session/handlers/chat.js +2 -751
  102. package/dist/src/session/handlers/control.js +1 -55
  103. package/dist/src/session/handlers/fs.js +1 -783
  104. package/dist/src/session/handlers/session-refresh.js +1 -47
  105. package/dist/src/session/handlers/skills.js +1 -121
  106. package/dist/src/session/handlers/title.js +1 -60
  107. package/dist/src/session/handlers/tool-detail.js +1 -218
  108. package/dist/src/session/manager.js +1 -319
  109. package/dist/src/session/projection.js +1 -54
  110. package/dist/src/session/queue.js +4 -317
  111. package/dist/src/session/remote-attachments.js +1 -72
  112. package/dist/src/session/store.js +3 -109
  113. package/dist/src/session/types.js +1 -4
  114. package/dist/src/skills/registry.js +15 -148
  115. package/dist/src/skills/setup.js +1 -101
  116. package/dist/src/tools/markdown-to-pdf.js +10 -346
  117. package/dist/src/upgrade/engine.js +3 -347
  118. package/package.json +3 -2
package/dist/src/index.js CHANGED
@@ -1,404 +1,2 @@
1
- // @arch docs/architecture/cli/daemon.md
2
- // @test src/__tests__/agents-e2e.ts
3
- // @test src/__tests__/daemon-autostart.test.ts
4
- import { Command } from 'commander';
5
- import chalk from 'chalk';
6
- import os from 'node:os';
7
- import fs from 'node:fs';
8
- import { loadConfig, saveConfig, configPath, getShennianDir, resolveShennianPath, } from './config/index.js';
9
- import { CliRelayClient } from './relay/client.js';
10
- import { registerPairCommand, runSmartStart } from './commands/pair.js';
11
- import { clearDaemonPidIfOwner, createDaemonInstanceId, clearDaemonLauncher, findRunningDaemonProcessIds, isRemoteAccessDisabled, registerDaemonCommand, writeDaemonPid, writeDaemonLauncher, } from './commands/daemon.js';
12
- import { registerAgentCommand } from './commands/agent.js';
13
- import { registerManagerCommand } from './commands/manager.js';
14
- import { registerExternalCommand } from './commands/external.js';
15
- import { registerUpgradeCommand } from './commands/upgrade.js';
16
- import { registerToolsCommand } from './commands/tools.js';
17
- import { SessionManager } from './session/manager.js';
18
- import { SERVERS, regionToUrl, urlToRegion } from './region.js';
19
- import { getCurrentVersion, handleStartupCrashCheck, checkForUpdate, isUpgradeVersionInCooldown, recordUpgradeFailure, } from './upgrade/engine.js';
20
- import { detectAgents } from './agents/detect.js';
21
- import { augmentProcessPath } from './env-path.js';
22
- augmentProcessPath();
23
- const cliVersion = getCurrentVersion();
24
- const AUTO_UPGRADE_INITIAL_DELAY_MS = 30_000;
25
- const AUTO_UPGRADE_POLL_INTERVAL_MS = 5 * 60_000;
26
- import { getCachedAgentInfos, resolveAgentInfos } from './agents/model-registry.js';
27
- import { initCliLogReporter, reportLog } from './log-reporter.js';
28
- import { isNativeFusionEnabled } from './native-fusion/config.js';
29
- import { NativeSessionFusionService } from './native-fusion/service.js';
30
- import { startDaemonLogRetention } from './daemon-log.js';
31
- const SHENNIAN_DIR = getShennianDir();
32
- const PID_FILE = resolveShennianPath('daemon.pid');
33
- function readDaemonPidFile() {
34
- try {
35
- const raw = fs.readFileSync(PID_FILE, 'utf-8').trim();
36
- if (raw.startsWith('{')) {
37
- const parsed = JSON.parse(raw);
38
- const pid = Number(parsed.pid);
39
- return Number.isInteger(pid) && pid > 0 ? pid : null;
40
- }
41
- const pid = parseInt(raw, 10);
42
- return Number.isInteger(pid) && pid > 0 ? pid : null;
43
- }
44
- catch {
45
- return null;
46
- }
47
- }
48
- function httpToWs(url) {
49
- return url.replace(/^https:\/\//, 'wss://').replace(/^http:\/\//, 'ws://');
50
- }
51
- function formatDisconnectInfo(info) {
52
- const parts = [
53
- `trigger=${info.trigger ?? 'unknown'}`,
54
- `phase=${info.phase}`,
55
- `code=${info.code ?? 'unknown'}`,
56
- `attempt=${info.reconnectAttempt}`,
57
- ];
58
- if (info.reason)
59
- parts.push(`reason=${info.reason}`);
60
- if (info.error)
61
- parts.push(`error=${info.error}`);
62
- return parts.join(' ');
63
- }
64
- async function waitForPidExit(pid, timeoutMs = 5000) {
65
- const startedAt = Date.now();
66
- while (Date.now() - startedAt < timeoutMs) {
67
- try {
68
- process.kill(pid, 0);
69
- }
70
- catch {
71
- return true;
72
- }
73
- await new Promise((resolve) => setTimeout(resolve, 100));
74
- }
75
- try {
76
- process.kill(pid, 0);
77
- return false;
78
- }
79
- catch {
80
- return true;
81
- }
82
- }
83
- const program = new Command();
84
- program.name('shennian').description('Shennian — AI Agent Control Plane').version(cliVersion);
85
- program
86
- .option('--api <url>', 'Server URL override')
87
- .option('--name <name>', 'Machine name', os.hostname())
88
- .action(async (opts) => {
89
- const config = loadConfig();
90
- const serverUrl = opts.api ?? process.env.SHENNIAN_DESKTOP_SERVER_URL ?? config.serverUrl ?? undefined;
91
- await runSmartStart(serverUrl, opts.name);
92
- });
93
- // run-service: internal command used by the background service process
94
- program
95
- .command('run-service', { hidden: true })
96
- .description('(internal) Connect to relay server, called by the background service')
97
- .option('--api <url>', 'Server URL override')
98
- .action(async (opts) => {
99
- const envFile = resolveShennianPath('env.json');
100
- try {
101
- const saved = JSON.parse(fs.readFileSync(envFile, 'utf-8'));
102
- for (const [k, v] of Object.entries(saved)) {
103
- if (!process.env[k])
104
- process.env[k] = v;
105
- }
106
- augmentProcessPath();
107
- }
108
- catch {
109
- // env.json may not exist yet
110
- }
111
- const logRetentionTimer = startDaemonLogRetention();
112
- if (isRemoteAccessDisabled()) {
113
- console.log(`[${new Date().toISOString()}] remote access disabled, service start skipped`);
114
- clearInterval(logRetentionTimer);
115
- process.exit(0);
116
- }
117
- // Single-instance guard. Service-manager starts are authoritative and may
118
- // need to take over from an older detached process after app/daemon upgrades.
119
- const serviceManagedStart = Boolean(process.env.INVOCATION_ID ||
120
- process.env.JOURNAL_STREAM ||
121
- process.env.SHENNIAN_DESKTOP_SERVER_URL);
122
- const stopExistingDaemon = async (oldPid, reason) => {
123
- console.log(`[${new Date().toISOString()}] ${reason} (PID ${oldPid})`);
124
- process.kill(oldPid, 'SIGTERM');
125
- const stopped = await waitForPidExit(oldPid);
126
- if (!stopped) {
127
- process.kill(oldPid, 'SIGKILL');
128
- await waitForPidExit(oldPid, 2000);
129
- }
130
- };
131
- try {
132
- const oldPid = readDaemonPidFile();
133
- if (oldPid && oldPid !== process.pid) {
134
- try {
135
- process.kill(oldPid, 0);
136
- if (serviceManagedStart) {
137
- await stopExistingDaemon(oldPid, 'managed start taking over from existing daemon');
138
- }
139
- else {
140
- console.log(`[${new Date().toISOString()}] daemon already running (PID ${oldPid}), skipping duplicate start`);
141
- process.exit(0);
142
- }
143
- }
144
- catch {
145
- // Stale pid; continue booting and overwrite it below.
146
- }
147
- }
148
- }
149
- catch {
150
- /* noop */
151
- }
152
- const orphanPids = findRunningDaemonProcessIds(process.pid);
153
- if (orphanPids.length > 0) {
154
- if (serviceManagedStart) {
155
- for (const orphanPid of orphanPids) {
156
- try {
157
- await stopExistingDaemon(orphanPid, 'managed start taking over from orphan daemon');
158
- }
159
- catch {
160
- // Keep booting; the normal pid-file guard below still protects the managed daemon.
161
- }
162
- }
163
- }
164
- else {
165
- console.log(`[${new Date().toISOString()}] daemon already running (PID ${orphanPids[0]}), skipping duplicate start`);
166
- process.exit(0);
167
- }
168
- }
169
- const daemonInstanceId = createDaemonInstanceId();
170
- writeDaemonPid(process.pid, daemonInstanceId, { version: cliVersion });
171
- writeDaemonLauncher(process.pid, undefined, daemonInstanceId);
172
- process.on('exit', () => {
173
- clearDaemonPidIfOwner(process.pid, daemonInstanceId);
174
- clearDaemonLauncher(daemonInstanceId);
175
- });
176
- // Crash detection: if we're recovering from a failed upgrade, rollback and exit
177
- const didRollback = await handleStartupCrashCheck();
178
- if (didRollback) {
179
- console.log(`[${new Date().toISOString()}] Rolled back to previous version, restarting...`);
180
- process.exit(0);
181
- }
182
- const config = loadConfig();
183
- if (!config.machineToken) {
184
- console.error(chalk.red('✗ Not paired yet. Run: shennian'));
185
- process.exit(1);
186
- }
187
- const serverUrl = opts.api ?? process.env.SHENNIAN_DESKTOP_SERVER_URL ?? config.serverUrl ?? SERVERS.cn.url;
188
- const wsBase = httpToWs(serverUrl);
189
- const wsUrl = `${wsBase}/relay/machine`;
190
- const currentCliVersion = getCurrentVersion();
191
- const detectedAgents = detectAgents();
192
- const agentList = detectedAgents.map((a) => a.type);
193
- const cachedAgentInfos = getCachedAgentInfos(detectedAgents);
194
- if (config.machineId) {
195
- initCliLogReporter(serverUrl, config.machineId);
196
- }
197
- console.log(`[${new Date().toISOString()}] Connecting to ${wsUrl}... (v${currentCliVersion}) agents: ${agentList.join(',')}`);
198
- reportLog({
199
- level: 'info',
200
- wsEvent: 'daemon.start',
201
- metadata: { version: currentCliVersion, agents: agentList },
202
- });
203
- let nativeFusion = null;
204
- const client = new CliRelayClient({
205
- serverUrl: wsUrl,
206
- machineToken: config.machineToken,
207
- cliVersion: currentCliVersion,
208
- agentList,
209
- onConnected: () => {
210
- console.log(`[${new Date().toISOString()}] ✓ Connected`);
211
- reportLog({ level: 'info', wsEvent: 'daemon.connected' });
212
- if (cachedAgentInfos.some((agent) => agent.models.length > 0)) {
213
- client.sendEvent({
214
- type: 'event',
215
- event: 'machine.agents',
216
- payload: {
217
- agentList,
218
- agents: cachedAgentInfos,
219
- },
220
- });
221
- }
222
- void resolveAgentInfos(detectedAgents, {
223
- serverUrl: config.serverUrl ?? serverUrl,
224
- authToken: config.machineToken ?? config.accessToken,
225
- })
226
- .then((agents) => {
227
- if (JSON.stringify(agents) === JSON.stringify(cachedAgentInfos))
228
- return;
229
- client.sendEvent({
230
- type: 'event',
231
- event: 'machine.agents',
232
- payload: {
233
- agentList,
234
- agents,
235
- },
236
- });
237
- })
238
- .catch(() => { });
239
- import('./upgrade/engine.js')
240
- .then(({ readUpgradeAttempt, clearUpgradeAttempt }) => {
241
- const attempt = readUpgradeAttempt();
242
- clearUpgradeAttempt();
243
- if (attempt) {
244
- console.log(`[${new Date().toISOString()}] [upgrade] Reporting success: ${attempt.from} → ${attempt.to}`);
245
- client.sendEvent({
246
- type: 'event',
247
- event: 'upgrade',
248
- payload: {
249
- state: 'success',
250
- machineId: 'self',
251
- from: attempt.from,
252
- to: attempt.to,
253
- },
254
- });
255
- }
256
- })
257
- .catch(() => { });
258
- void scheduleAutoUpgrade(client, config.autoUpgrade ?? 'patch', currentCliVersion);
259
- nativeFusion?.handleConnected();
260
- },
261
- onDisconnected: (info) => {
262
- console.log(`[${new Date().toISOString()}] ⚠ Disconnected, reconnecting... ${formatDisconnectInfo(info)}`);
263
- reportLog({
264
- level: 'warn',
265
- wsEvent: 'daemon.disconnected',
266
- metadata: {
267
- code: info.code,
268
- reason: info.reason,
269
- error: info.error,
270
- phase: info.phase,
271
- trigger: info.trigger,
272
- reconnectAttempt: info.reconnectAttempt,
273
- },
274
- });
275
- },
276
- onReq: (req) => {
277
- console.log(`[${new Date().toISOString()}] [req] ${req.method}`);
278
- reportLog({
279
- level: 'info',
280
- type: 'ws',
281
- wsEvent: req.method,
282
- wsDirection: 'in',
283
- traceId: req.traceId,
284
- });
285
- void sessionManager.handleReq(req);
286
- },
287
- });
288
- nativeFusion =
289
- isNativeFusionEnabled()
290
- ? new NativeSessionFusionService(client)
291
- : null;
292
- const sessionManager = new SessionManager(client, nativeFusion, currentCliVersion);
293
- fs.mkdirSync(SHENNIAN_DIR, { recursive: true });
294
- writeDaemonPid(process.pid, daemonInstanceId, { version: currentCliVersion });
295
- writeDaemonLauncher(process.pid, undefined, daemonInstanceId);
296
- client.connect();
297
- process.stdin.resume();
298
- const shutdown = () => {
299
- console.log(chalk.gray('\nDisconnecting...'));
300
- reportLog({ level: 'info', wsEvent: 'daemon.stop' });
301
- clearInterval(logRetentionTimer);
302
- sessionManager.cleanup();
303
- nativeFusion?.stop();
304
- client.disconnect();
305
- clearDaemonPidIfOwner(process.pid, daemonInstanceId);
306
- clearDaemonLauncher(daemonInstanceId);
307
- process.exit(0);
308
- };
309
- process.on('SIGINT', shutdown);
310
- process.on('SIGTERM', shutdown);
311
- });
312
- // config: view and modify settings
313
- const configCmd = program.command('config').description('View or modify configuration');
314
- configCmd
315
- .command('show', { isDefault: true })
316
- .description('Show current configuration')
317
- .action(() => {
318
- console.log(`Config file: ${configPath}`);
319
- const config = loadConfig();
320
- const display = { ...config };
321
- if (display.machineToken)
322
- display.machineToken = display.machineToken.slice(0, 12) + '...';
323
- if (display.serverUrl) {
324
- const region = urlToRegion(display.serverUrl);
325
- console.log(`Region: ${region} (${SERVERS[region].label})`);
326
- }
327
- console.log(JSON.stringify(display, null, 2));
328
- });
329
- configCmd
330
- .command('set')
331
- .description('Update a config value')
332
- .argument('<key>', 'Config key (e.g. "server")')
333
- .argument('<value>', 'Config value (e.g. "cn" or "global")')
334
- .action((key, value) => {
335
- const config = loadConfig();
336
- if (key === 'server') {
337
- if (value !== 'cn' && value !== 'global') {
338
- console.error(chalk.red('✗ Value must be "cn" or "global"'));
339
- process.exit(1);
340
- }
341
- const region = value;
342
- config.serverUrl = regionToUrl(region);
343
- saveConfig(config);
344
- console.log(chalk.green(`✓ Server set to ${SERVERS[region].label}`));
345
- console.log(chalk.yellow(' Restart the background service for this to take effect: shennian stop && shennian start'));
346
- return;
347
- }
348
- console.error(chalk.red(`✗ Unknown config key: ${key}. Supported: server`));
349
- process.exit(1);
350
- });
351
- registerPairCommand(program);
352
- registerDaemonCommand(program);
353
- registerAgentCommand(program);
354
- registerManagerCommand(program);
355
- registerExternalCommand(program);
356
- registerUpgradeCommand(program);
357
- registerToolsCommand(program);
358
- program.parse();
359
- // ─── Auto-upgrade helper ──────────────────────────────────────────────────────
360
- async function scheduleAutoUpgrade(client, policy, currentVersion) {
361
- if (policy === 'none')
362
- return;
363
- let upgradeInFlight = false;
364
- const tick = async () => {
365
- if (upgradeInFlight)
366
- return;
367
- let result;
368
- try {
369
- result = await checkForUpdate(currentVersion);
370
- }
371
- catch {
372
- return; // silently skip on network error
373
- }
374
- if (!result.hasUpdate)
375
- return;
376
- const { changeType, current, latest } = result;
377
- // Respect the policy
378
- if (policy === 'patch' && changeType !== 'patch')
379
- return;
380
- if (policy === 'minor' && changeType === 'major')
381
- return;
382
- if (isUpgradeVersionInCooldown(latest))
383
- return;
384
- console.log(`[${new Date().toISOString()}] [upgrade] ${current} → ${latest} (${changeType}), auto-upgrading...`);
385
- upgradeInFlight = true;
386
- try {
387
- const { handleUpgradeStart } = await import('./commands/upgrade.js');
388
- // Use a dummy reqId since this is self-triggered
389
- await handleUpgradeStart(client, 'auto-upgrade', latest, { currentVersion });
390
- }
391
- catch (err) {
392
- const message = err instanceof Error ? err.message : String(err);
393
- const failure = recordUpgradeFailure(latest, message);
394
- console.log(`[${new Date().toISOString()}] [upgrade] ${latest} failed, retry after ${new Date(failure.nextRetryAt).toISOString()}: ${message}`);
395
- }
396
- finally {
397
- upgradeInFlight = false;
398
- }
399
- };
400
- // Delay slightly so we don't hit npm on every cold start during development,
401
- // then keep polling so a bad published patch can be superseded by a good one.
402
- setTimeout(() => void tick(), AUTO_UPGRADE_INITIAL_DELAY_MS);
403
- setInterval(() => void tick(), AUTO_UPGRADE_POLL_INTERVAL_MS);
404
- }
1
+ import{Command as V}from"commander";import u from"chalk";import M from"node:os";import R from"node:fs";import{loadConfig as w,saveConfig as G,configPath as J,getShennianDir as j,resolveShennianPath as A}from"./config/index.js";import{CliRelayClient as H}from"./relay/client.js";import{registerPairCommand as K,runSmartStart as B}from"./commands/pair.js";import{clearDaemonPidIfOwner as N,createDaemonInstanceId as W,clearDaemonLauncher as O,findRunningDaemonProcessIds as Y,isRemoteAccessDisabled as q,registerDaemonCommand as z,writeDaemonPid as T,writeDaemonLauncher as _}from"./commands/daemon.js";import{registerAgentCommand as Q}from"./commands/agent.js";import{registerManagerCommand as X}from"./commands/manager.js";import{registerExternalCommand as Z}from"./commands/external.js";import{registerUpgradeCommand as ee}from"./commands/upgrade.js";import{registerToolsCommand as ne}from"./commands/tools.js";import{SessionManager as oe}from"./session/manager.js";import{SERVERS as k,regionToUrl as te,urlToRegion as re}from"./region.js";import{getCurrentVersion as P,handleStartupCrashCheck as se,checkForUpdate as ae,isUpgradeVersionInCooldown as ie,recordUpgradeFailure as ce}from"./upgrade/engine.js";import{detectAgents as le}from"./agents/detect.js";import{augmentProcessPath as L}from"./env-path.js";L();const b=P(),pe=3e4,de=5*6e4;import{getCachedAgentInfos as me,resolveAgentInfos as ge}from"./agents/model-registry.js";import{initCliLogReporter as ue,reportLog as v}from"./log-reporter.js";import{isNativeFusionEnabled as fe}from"./native-fusion/config.js";import{NativeSessionFusionService as he}from"./native-fusion/service.js";import{startDaemonLogRetention as ve}from"./daemon-log.js";const Se=j(),Ie=A("daemon.pid");function we(){try{const n=R.readFileSync(Ie,"utf-8").trim();if(n.startsWith("{")){const t=JSON.parse(n),r=Number(t.pid);return Number.isInteger(r)&&r>0?r:null}const o=parseInt(n,10);return Number.isInteger(o)&&o>0?o:null}catch{return null}}function De(n){return n.replace(/^https:\/\//,"wss://").replace(/^http:\/\//,"ws://")}function ye(n){const o=[`trigger=${n.trigger??"unknown"}`,`phase=${n.phase}`,`code=${n.code??"unknown"}`,`attempt=${n.reconnectAttempt}`];return n.reason&&o.push(`reason=${n.reason}`),n.error&&o.push(`error=${n.error}`),o.join(" ")}async function x(n,o=5e3){const t=Date.now();for(;Date.now()-t<o;){try{process.kill(n,0)}catch{return!0}await new Promise(r=>setTimeout(r,100))}try{return process.kill(n,0),!1}catch{return!0}}const i=new V;i.name("shennian").description("Shennian \u2014 AI Agent Control Plane").version(b),i.option("--api <url>","Server URL override").option("--name <name>","Machine name",M.hostname()).action(async n=>{const o=w(),t=n.api??process.env.SHENNIAN_DESKTOP_SERVER_URL??o.serverUrl??void 0;await B(t,n.name)}),i.command("run-service",{hidden:!0}).description("(internal) Connect to relay server, called by the background service").option("--api <url>","Server URL override").action(async n=>{const o=A("env.json");try{const e=JSON.parse(R.readFileSync(o,"utf-8"));for(const[g,p]of Object.entries(e))process.env[g]||(process.env[g]=p);L()}catch{}const t=ve();q()&&(console.log(`[${new Date().toISOString()}] remote access disabled, service start skipped`),clearInterval(t),process.exit(0));const r=!!(process.env.INVOCATION_ID||process.env.JOURNAL_STREAM||process.env.SHENNIAN_DESKTOP_SERVER_URL),f=async(e,g)=>{console.log(`[${new Date().toISOString()}] ${g} (PID ${e})`),process.kill(e,"SIGTERM"),await x(e)||(process.kill(e,"SIGKILL"),await x(e,2e3))};try{const e=we();if(e&&e!==process.pid)try{process.kill(e,0),r?await f(e,"managed start taking over from existing daemon"):(console.log(`[${new Date().toISOString()}] daemon already running (PID ${e}), skipping duplicate start`),process.exit(0))}catch{}}catch{}const d=Y(process.pid);if(d.length>0)if(r)for(const e of d)try{await f(e,"managed start taking over from orphan daemon")}catch{}else console.log(`[${new Date().toISOString()}] daemon already running (PID ${d[0]}), skipping duplicate start`),process.exit(0);const a=W();T(process.pid,a,{version:b}),_(process.pid,void 0,a),process.on("exit",()=>{N(process.pid,a),O(a)}),await se()&&(console.log(`[${new Date().toISOString()}] Rolled back to previous version, restarting...`),process.exit(0));const s=w();s.machineToken||(console.error(u.red("\u2717 Not paired yet. Run: shennian")),process.exit(1));const c=n.api??process.env.SHENNIAN_DESKTOP_SERVER_URL??s.serverUrl??k.cn.url,S=`${De(c)}/relay/machine`,m=P(),y=le(),h=y.map(e=>e.type),$=me(y);s.machineId&&ue(c,s.machineId),console.log(`[${new Date().toISOString()}] Connecting to ${S}... (v${m}) agents: ${h.join(",")}`),v({level:"info",wsEvent:"daemon.start",metadata:{version:m,agents:h}});let I=null;const l=new H({serverUrl:S,machineToken:s.machineToken,cliVersion:m,agentList:h,onConnected:()=>{console.log(`[${new Date().toISOString()}] \u2713 Connected`),v({level:"info",wsEvent:"daemon.connected"}),$.some(e=>e.models.length>0)&&l.sendEvent({type:"event",event:"machine.agents",payload:{agentList:h,agents:$}}),ge(y,{serverUrl:s.serverUrl??c,authToken:s.machineToken??s.accessToken}).then(e=>{JSON.stringify(e)!==JSON.stringify($)&&l.sendEvent({type:"event",event:"machine.agents",payload:{agentList:h,agents:e}})}).catch(()=>{}),import("./upgrade/engine.js").then(({readUpgradeAttempt:e,clearUpgradeAttempt:g})=>{const p=e();g(),p&&(console.log(`[${new Date().toISOString()}] [upgrade] Reporting success: ${p.from} \u2192 ${p.to}`),l.sendEvent({type:"event",event:"upgrade",payload:{state:"success",machineId:"self",from:p.from,to:p.to}}))}).catch(()=>{}),$e(l,s.autoUpgrade??"patch",m),I?.handleConnected()},onDisconnected:e=>{console.log(`[${new Date().toISOString()}] \u26A0 Disconnected, reconnecting... ${ye(e)}`),v({level:"warn",wsEvent:"daemon.disconnected",metadata:{code:e.code,reason:e.reason,error:e.error,phase:e.phase,trigger:e.trigger,reconnectAttempt:e.reconnectAttempt}})},onReq:e=>{console.log(`[${new Date().toISOString()}] [req] ${e.method}`),v({level:"info",type:"ws",wsEvent:e.method,wsDirection:"in",traceId:e.traceId}),U.handleReq(e)}});I=fe()?new he(l):null;const U=new oe(l,I,m);R.mkdirSync(Se,{recursive:!0}),T(process.pid,a,{version:m}),_(process.pid,void 0,a),l.connect(),process.stdin.resume();const C=()=>{console.log(u.gray(`
2
+ Disconnecting...`)),v({level:"info",wsEvent:"daemon.stop"}),clearInterval(t),U.cleanup(),I?.stop(),l.disconnect(),N(process.pid,a),O(a),process.exit(0)};process.on("SIGINT",C),process.on("SIGTERM",C)});const F=i.command("config").description("View or modify configuration");F.command("show",{isDefault:!0}).description("Show current configuration").action(()=>{console.log(`Config file: ${J}`);const o={...w()};if(o.machineToken&&(o.machineToken=o.machineToken.slice(0,12)+"..."),o.serverUrl){const t=re(o.serverUrl);console.log(`Region: ${t} (${k[t].label})`)}console.log(JSON.stringify(o,null,2))}),F.command("set").description("Update a config value").argument("<key>",'Config key (e.g. "server")').argument("<value>",'Config value (e.g. "cn" or "global")').action((n,o)=>{const t=w();if(n==="server"){o!=="cn"&&o!=="global"&&(console.error(u.red('\u2717 Value must be "cn" or "global"')),process.exit(1));const r=o;t.serverUrl=te(r),G(t),console.log(u.green(`\u2713 Server set to ${k[r].label}`)),console.log(u.yellow(" Restart the background service for this to take effect: shennian stop && shennian start"));return}console.error(u.red(`\u2717 Unknown config key: ${n}. Supported: server`)),process.exit(1)}),K(i),z(i),Q(i),X(i),Z(i),ee(i),ne(i),i.parse();async function $e(n,o,t){if(o==="none")return;let r=!1;const f=async()=>{if(r)return;let d;try{d=await ae(t)}catch{return}if(!d.hasUpdate)return;const{changeType:a,current:E,latest:s}=d;if(!(o==="patch"&&a!=="patch")&&!(o==="minor"&&a==="major")&&!ie(s)){console.log(`[${new Date().toISOString()}] [upgrade] ${E} \u2192 ${s} (${a}), auto-upgrading...`),r=!0;try{const{handleUpgradeStart:c}=await import("./commands/upgrade.js");await c(n,"auto-upgrade",s,{currentVersion:t})}catch(c){const D=c instanceof Error?c.message:String(c),S=ce(s,D);console.log(`[${new Date().toISOString()}] [upgrade] ${s} failed, retry after ${new Date(S.nextRetryAt).toISOString()}: ${D}`)}finally{r=!1}}};setTimeout(()=>{f()},pe),setInterval(()=>{f()},de)}
@@ -1,16 +1 @@
1
- import crypto from 'node:crypto';
2
- let _serverUrl;
3
- let _machineId;
4
- export function initCliLogReporter(serverUrl, machineId) {
5
- _serverUrl = serverUrl.replace(/\/$/, '');
6
- _machineId = machineId;
7
- }
8
- export function generateTraceId() {
9
- return crypto.randomBytes(8).toString('hex');
10
- }
11
- export function reportLog(entry) {
12
- if (!_serverUrl || !_machineId)
13
- return;
14
- // Remote DB log reporting is intentionally disabled; keep the API for callers.
15
- void entry;
16
- }
1
+ import n from"node:crypto";let e,t;function p(r,o){e=r.replace(/\/$/,""),t=o}function c(){return n.randomBytes(8).toString("hex")}function a(r){}export{c as generateTraceId,p as initCliLogReporter,a as reportLog};
@@ -1,34 +1,32 @@
1
- // @arch docs/features/manager-agent.md
2
- // @test src/__tests__/manager-runtime.test.ts
3
- export const MANAGER_SYSTEM_PROMPT = `你是项目经理,是当前项目的管理者。
1
+ const s=`\u4F60\u662F\u9879\u76EE\u7ECF\u7406\uFF0C\u662F\u5F53\u524D\u9879\u76EE\u7684\u7BA1\u7406\u8005\u3002
4
2
 
5
- 你的职责:
6
- - 理解用户目标。
7
- - 拆解任务。
8
- - 创建、指派、观察和停止同一项目目录下的 worker Agent session
9
- - 汇总 worker 结果。
10
- - 判断是否需要继续等待、调整安排、询问用户或验收。
11
- - 在项目 .shennian/ 目录下维护必要的计划、记录和项目记忆。
3
+ \u4F60\u7684\u804C\u8D23\uFF1A
4
+ - \u7406\u89E3\u7528\u6237\u76EE\u6807\u3002
5
+ - \u62C6\u89E3\u4EFB\u52A1\u3002
6
+ - \u521B\u5EFA\u3001\u6307\u6D3E\u3001\u89C2\u5BDF\u548C\u505C\u6B62\u540C\u4E00\u9879\u76EE\u76EE\u5F55\u4E0B\u7684 worker Agent session\u3002
7
+ - \u6C47\u603B worker \u7ED3\u679C\u3002
8
+ - \u5224\u65AD\u662F\u5426\u9700\u8981\u7EE7\u7EED\u7B49\u5F85\u3001\u8C03\u6574\u5B89\u6392\u3001\u8BE2\u95EE\u7528\u6237\u6216\u9A8C\u6536\u3002
9
+ - \u5728\u9879\u76EE .shennian/ \u76EE\u5F55\u4E0B\u7EF4\u62A4\u5FC5\u8981\u7684\u8BA1\u5212\u3001\u8BB0\u5F55\u548C\u9879\u76EE\u8BB0\u5FC6\u3002
12
10
 
13
- 你的边界:
14
- - 不要把自己当作主要执行者。
15
- - 不要直接编辑业务代码,除非用户明确要求你亲自执行。
16
- - 可以读取文件、搜索项目和检查上下文,以便做判断。
17
- - 需要修改代码、运行测试、调研方案时,优先创建或指派 worker
18
- - 每次收到新任务、补充要求、纠偏或外部消息时,先用 sessions list 查看当前同项目 worker;如果可能相关,再用 sessions read 读取必要摘要后判断是否复用。
19
- - 如果已有 worker 正在处理同一目标、同一功能区、同一文件范围或同一问题链路,优先用 sessions send 把新要求发给这个 worker;即使 worker 正忙也可以发送,默认会进入本机队列,不要因为它忙就新建 worker
20
- - 只有没有相关 worker、现有 worker 已明显不适合继续推进、或任务需要并行拆分给不同专长时,才创建新的 worker
21
- - 创建或指派 worker 后,除非用户明确要求你当场继续调度,否则回复用户已安排并结束当前 turn;不要主动轮询 worker 状态,神念会在 worker 终态或健康摘要到来时重新唤醒你。
22
- - sessions read 返回的是给管理者看的简洁进展、工具摘要和最终结果,不是原始流式 token;不要要求读取或转述完整流式日志。
23
- - 只能管理与你处于同一台机器、同一项目目录的会话;不要跨机器或跨项目调度。
24
- - 不要无限循环;没有明确下一步时询问用户或结束当前 turn 等待系统事件。
25
- - 不要自己设置定时唤醒;神念会在用户消息、worker 终态或 worker 长运行健康摘要到来时唤醒你。
26
- - 外部消息通道事件会像普通用户消息一样送达,格式类似“外部消息 / 发送人”后跟消息内容,可能是合并消息,也可能包含图片、视频或文件 URL
27
- - 外部消息是否需要回复、追问、忽略、转交内部负责人,或创建/指派 worker,由你根据项目上下文显式判断。
28
- - 对外你是当前项目的项目经理,不要自称神念、Manager Agent worker,也不要解释内部调度机制;只在需要时用“我这边/我们这边”沟通。
29
- - 不要把所有细节塞进对话上下文;需要长期保存的信息写到项目 .shennian/ 下。
11
+ \u4F60\u7684\u8FB9\u754C\uFF1A
12
+ - \u4E0D\u8981\u628A\u81EA\u5DF1\u5F53\u4F5C\u4E3B\u8981\u6267\u884C\u8005\u3002
13
+ - \u4E0D\u8981\u76F4\u63A5\u7F16\u8F91\u4E1A\u52A1\u4EE3\u7801\uFF0C\u9664\u975E\u7528\u6237\u660E\u786E\u8981\u6C42\u4F60\u4EB2\u81EA\u6267\u884C\u3002
14
+ - \u53EF\u4EE5\u8BFB\u53D6\u6587\u4EF6\u3001\u641C\u7D22\u9879\u76EE\u548C\u68C0\u67E5\u4E0A\u4E0B\u6587\uFF0C\u4EE5\u4FBF\u505A\u5224\u65AD\u3002
15
+ - \u9700\u8981\u4FEE\u6539\u4EE3\u7801\u3001\u8FD0\u884C\u6D4B\u8BD5\u3001\u8C03\u7814\u65B9\u6848\u65F6\uFF0C\u4F18\u5148\u521B\u5EFA\u6216\u6307\u6D3E worker\u3002
16
+ - \u6BCF\u6B21\u6536\u5230\u65B0\u4EFB\u52A1\u3001\u8865\u5145\u8981\u6C42\u3001\u7EA0\u504F\u6216\u5916\u90E8\u6D88\u606F\u65F6\uFF0C\u5148\u7528 sessions list \u67E5\u770B\u5F53\u524D\u540C\u9879\u76EE worker\uFF1B\u5982\u679C\u53EF\u80FD\u76F8\u5173\uFF0C\u518D\u7528 sessions read \u8BFB\u53D6\u5FC5\u8981\u6458\u8981\u540E\u5224\u65AD\u662F\u5426\u590D\u7528\u3002
17
+ - \u5982\u679C\u5DF2\u6709 worker \u6B63\u5728\u5904\u7406\u540C\u4E00\u76EE\u6807\u3001\u540C\u4E00\u529F\u80FD\u533A\u3001\u540C\u4E00\u6587\u4EF6\u8303\u56F4\u6216\u540C\u4E00\u95EE\u9898\u94FE\u8DEF\uFF0C\u4F18\u5148\u7528 sessions send \u628A\u65B0\u8981\u6C42\u53D1\u7ED9\u8FD9\u4E2A worker\uFF1B\u5373\u4F7F worker \u6B63\u5FD9\u4E5F\u53EF\u4EE5\u53D1\u9001\uFF0C\u9ED8\u8BA4\u4F1A\u8FDB\u5165\u672C\u673A\u961F\u5217\uFF0C\u4E0D\u8981\u56E0\u4E3A\u5B83\u5FD9\u5C31\u65B0\u5EFA worker\u3002
18
+ - \u53EA\u6709\u6CA1\u6709\u76F8\u5173 worker\u3001\u73B0\u6709 worker \u5DF2\u660E\u663E\u4E0D\u9002\u5408\u7EE7\u7EED\u63A8\u8FDB\u3001\u6216\u4EFB\u52A1\u9700\u8981\u5E76\u884C\u62C6\u5206\u7ED9\u4E0D\u540C\u4E13\u957F\u65F6\uFF0C\u624D\u521B\u5EFA\u65B0\u7684 worker\u3002
19
+ - \u521B\u5EFA\u6216\u6307\u6D3E worker \u540E\uFF0C\u9664\u975E\u7528\u6237\u660E\u786E\u8981\u6C42\u4F60\u5F53\u573A\u7EE7\u7EED\u8C03\u5EA6\uFF0C\u5426\u5219\u56DE\u590D\u7528\u6237\u5DF2\u5B89\u6392\u5E76\u7ED3\u675F\u5F53\u524D turn\uFF1B\u4E0D\u8981\u4E3B\u52A8\u8F6E\u8BE2 worker \u72B6\u6001\uFF0C\u795E\u5FF5\u4F1A\u5728 worker \u7EC8\u6001\u6216\u5065\u5EB7\u6458\u8981\u5230\u6765\u65F6\u91CD\u65B0\u5524\u9192\u4F60\u3002
20
+ - sessions read \u8FD4\u56DE\u7684\u662F\u7ED9\u7BA1\u7406\u8005\u770B\u7684\u7B80\u6D01\u8FDB\u5C55\u3001\u5DE5\u5177\u6458\u8981\u548C\u6700\u7EC8\u7ED3\u679C\uFF0C\u4E0D\u662F\u539F\u59CB\u6D41\u5F0F token\uFF1B\u4E0D\u8981\u8981\u6C42\u8BFB\u53D6\u6216\u8F6C\u8FF0\u5B8C\u6574\u6D41\u5F0F\u65E5\u5FD7\u3002
21
+ - \u53EA\u80FD\u7BA1\u7406\u4E0E\u4F60\u5904\u4E8E\u540C\u4E00\u53F0\u673A\u5668\u3001\u540C\u4E00\u9879\u76EE\u76EE\u5F55\u7684\u4F1A\u8BDD\uFF1B\u4E0D\u8981\u8DE8\u673A\u5668\u6216\u8DE8\u9879\u76EE\u8C03\u5EA6\u3002
22
+ - \u4E0D\u8981\u65E0\u9650\u5FAA\u73AF\uFF1B\u6CA1\u6709\u660E\u786E\u4E0B\u4E00\u6B65\u65F6\u8BE2\u95EE\u7528\u6237\u6216\u7ED3\u675F\u5F53\u524D turn \u7B49\u5F85\u7CFB\u7EDF\u4E8B\u4EF6\u3002
23
+ - \u4E0D\u8981\u81EA\u5DF1\u8BBE\u7F6E\u5B9A\u65F6\u5524\u9192\uFF1B\u795E\u5FF5\u4F1A\u5728\u7528\u6237\u6D88\u606F\u3001worker \u7EC8\u6001\u6216 worker \u957F\u8FD0\u884C\u5065\u5EB7\u6458\u8981\u5230\u6765\u65F6\u5524\u9192\u4F60\u3002
24
+ - \u5916\u90E8\u6D88\u606F\u901A\u9053\u4E8B\u4EF6\u4F1A\u50CF\u666E\u901A\u7528\u6237\u6D88\u606F\u4E00\u6837\u9001\u8FBE\uFF0C\u683C\u5F0F\u7C7B\u4F3C\u201C\u5916\u90E8\u6D88\u606F / \u53D1\u9001\u4EBA\u201D\u540E\u8DDF\u6D88\u606F\u5185\u5BB9\uFF0C\u53EF\u80FD\u662F\u5408\u5E76\u6D88\u606F\uFF0C\u4E5F\u53EF\u80FD\u5305\u542B\u56FE\u7247\u3001\u89C6\u9891\u6216\u6587\u4EF6 URL\u3002
25
+ - \u5916\u90E8\u6D88\u606F\u662F\u5426\u9700\u8981\u56DE\u590D\u3001\u8FFD\u95EE\u3001\u5FFD\u7565\u3001\u8F6C\u4EA4\u5185\u90E8\u8D1F\u8D23\u4EBA\uFF0C\u6216\u521B\u5EFA/\u6307\u6D3E worker\uFF0C\u7531\u4F60\u6839\u636E\u9879\u76EE\u4E0A\u4E0B\u6587\u663E\u5F0F\u5224\u65AD\u3002
26
+ - \u5BF9\u5916\u4F60\u662F\u5F53\u524D\u9879\u76EE\u7684\u9879\u76EE\u7ECF\u7406\uFF0C\u4E0D\u8981\u81EA\u79F0\u795E\u5FF5\u3001Manager Agent \u6216 worker\uFF0C\u4E5F\u4E0D\u8981\u89E3\u91CA\u5185\u90E8\u8C03\u5EA6\u673A\u5236\uFF1B\u53EA\u5728\u9700\u8981\u65F6\u7528\u201C\u6211\u8FD9\u8FB9/\u6211\u4EEC\u8FD9\u8FB9\u201D\u6C9F\u901A\u3002
27
+ - \u4E0D\u8981\u628A\u6240\u6709\u7EC6\u8282\u585E\u8FDB\u5BF9\u8BDD\u4E0A\u4E0B\u6587\uFF1B\u9700\u8981\u957F\u671F\u4FDD\u5B58\u7684\u4FE1\u606F\u5199\u5230\u9879\u76EE .shennian/ \u4E0B\u3002
30
28
 
31
- 需要管理 worker 或外部通道时,使用本地命令:
29
+ \u9700\u8981\u7BA1\u7406 worker \u6216\u5916\u90E8\u901A\u9053\u65F6\uFF0C\u4F7F\u7528\u672C\u5730\u547D\u4EE4\uFF1A
32
30
  - shennian manager sessions list --json
33
31
  - shennian manager sessions start --agent <codex|claude|gemini|cursor|opencode|pi|custom:name> --workdir <path> --message <text>
34
32
  - shennian manager sessions send --session-id <id> --message <text>
@@ -36,13 +34,10 @@ export const MANAGER_SYSTEM_PROMPT = `你是项目经理,是当前项目的管
36
34
  - shennian manager sessions queue list --session-id <id> --json
37
35
  - shennian manager sessions queue edit --session-id <id> --message-id <queueMessageId> --message <text>
38
36
  - shennian manager sessions queue delete --session-id <id> --message-id <queueMessageId>
39
- - shennian manager sessions stop --session-id <id>(终止正在运行的 worker;也可用 terminate/kill 别名)
37
+ - shennian manager sessions stop --session-id <id>\uFF08\u7EC8\u6B62\u6B63\u5728\u8FD0\u884C\u7684 worker\uFF1B\u4E5F\u53EF\u7528 terminate/kill \u522B\u540D\uFF09
40
38
  - shennian manager sessions read --session-id <id> --limit 200 --json
41
39
  - shennian manager memory path
42
40
 
43
- 可创建的 worker Agent 包括 Codex、Claude Code、Gemini、Cursor、opencode、Nian,以及本机 custom agent(custom:<name>)。默认用 sessions send 排队发送 worker 消息:worker 正忙时消息会在本机 daemon 队列里等待,worker 空闲时自动执行。队列里的未执行消息可以 list/edit/delete;已经开始执行的消息不能编辑或删除,只能 stop 后重新发送。只有明确需要打断顺序时才使用 --direct
41
+ \u53EF\u521B\u5EFA\u7684 worker Agent \u5305\u62EC Codex\u3001Claude Code\u3001Gemini\u3001Cursor\u3001opencode\u3001Nian\uFF0C\u4EE5\u53CA\u672C\u673A custom agent\uFF08custom:<name>\uFF09\u3002\u9ED8\u8BA4\u7528 sessions send \u6392\u961F\u53D1\u9001 worker \u6D88\u606F\uFF1Aworker \u6B63\u5FD9\u65F6\u6D88\u606F\u4F1A\u5728\u672C\u673A daemon \u961F\u5217\u91CC\u7B49\u5F85\uFF0Cworker \u7A7A\u95F2\u65F6\u81EA\u52A8\u6267\u884C\u3002\u961F\u5217\u91CC\u7684\u672A\u6267\u884C\u6D88\u606F\u53EF\u4EE5 list/edit/delete\uFF1B\u5DF2\u7ECF\u5F00\u59CB\u6267\u884C\u7684\u6D88\u606F\u4E0D\u80FD\u7F16\u8F91\u6216\u5220\u9664\uFF0C\u53EA\u80FD stop \u540E\u91CD\u65B0\u53D1\u9001\u3002\u53EA\u6709\u660E\u786E\u9700\u8981\u6253\u65AD\u987A\u5E8F\u65F6\u624D\u4F7F\u7528 --direct\u3002
44
42
 
45
- 这些命令已经由神念注入当前 Manager 身份和同项目权限边界。不要尝试伪造 Manager session id。`;
46
- export function buildManagerPrompt(userText) {
47
- return userText;
48
- }
43
+ \u8FD9\u4E9B\u547D\u4EE4\u5DF2\u7ECF\u7531\u795E\u5FF5\u6CE8\u5165\u5F53\u524D Manager \u8EAB\u4EFD\u548C\u540C\u9879\u76EE\u6743\u9650\u8FB9\u754C\u3002\u4E0D\u8981\u5C1D\u8BD5\u4F2A\u9020 Manager session id\u3002`;function n(e){return e}export{s as MANAGER_SYSTEM_PROMPT,n as buildManagerPrompt};