shennian 0.2.6 → 0.2.8

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 (85) hide show
  1. package/dist/bin/shennian.d.ts +2 -0
  2. package/dist/bin/shennian.js +2 -0
  3. package/dist/src/agents/adapter.d.ts +35 -0
  4. package/dist/src/agents/adapter.js +19 -0
  5. package/dist/src/agents/claude.d.ts +25 -0
  6. package/dist/src/agents/claude.js +234 -0
  7. package/dist/src/agents/codex.d.ts +52 -0
  8. package/dist/src/agents/codex.js +829 -0
  9. package/dist/src/agents/command-spec.d.ts +36 -0
  10. package/dist/src/agents/command-spec.js +303 -0
  11. package/dist/src/agents/cursor.d.ts +22 -0
  12. package/dist/src/agents/cursor.js +248 -0
  13. package/dist/src/agents/custom.d.ts +30 -0
  14. package/dist/src/agents/custom.js +210 -0
  15. package/dist/src/agents/detect.d.ts +9 -0
  16. package/dist/src/agents/detect.js +46 -0
  17. package/dist/src/agents/gemini.d.ts +17 -0
  18. package/dist/src/agents/gemini.js +172 -0
  19. package/dist/src/agents/model-registry/cache.d.ts +4 -0
  20. package/dist/src/agents/model-registry/cache.js +37 -0
  21. package/dist/src/agents/model-registry/discovery.d.ts +4 -0
  22. package/dist/src/agents/model-registry/discovery.js +166 -0
  23. package/dist/src/agents/model-registry/parsers.d.ts +11 -0
  24. package/dist/src/agents/model-registry/parsers.js +349 -0
  25. package/dist/src/agents/model-registry/runner.d.ts +6 -0
  26. package/dist/src/agents/model-registry/runner.js +29 -0
  27. package/dist/src/agents/model-registry/service.d.ts +6 -0
  28. package/dist/src/agents/model-registry/service.js +71 -0
  29. package/dist/src/agents/model-registry/types.d.ts +30 -0
  30. package/dist/src/agents/model-registry/types.js +8 -0
  31. package/dist/src/agents/model-registry.d.ts +13 -0
  32. package/dist/src/agents/model-registry.js +15 -0
  33. package/dist/src/agents/openclaw.d.ts +20 -0
  34. package/dist/src/agents/openclaw.js +273 -0
  35. package/dist/src/agents/pi.d.ts +51 -0
  36. package/dist/src/agents/pi.js +793 -0
  37. package/dist/src/commands/agent.d.ts +2 -0
  38. package/dist/src/commands/agent.js +131 -0
  39. package/dist/src/commands/daemon.d.ts +35 -0
  40. package/dist/src/commands/daemon.js +612 -0
  41. package/dist/src/commands/pair-qr.d.ts +4 -0
  42. package/dist/src/commands/pair-qr.js +6 -0
  43. package/dist/src/commands/pair.d.ts +8 -0
  44. package/dist/src/commands/pair.js +162 -0
  45. package/dist/src/commands/upgrade.d.ts +5 -0
  46. package/dist/src/commands/upgrade.js +145 -0
  47. package/dist/src/config/index.d.ts +32 -0
  48. package/dist/src/config/index.js +31 -0
  49. package/dist/src/fs/handler.d.ts +26 -0
  50. package/dist/src/fs/handler.js +130 -0
  51. package/dist/src/fs/security.d.ts +2 -0
  52. package/dist/src/fs/security.js +32 -0
  53. package/dist/src/index.d.ts +1 -0
  54. package/dist/src/index.js +277 -0
  55. package/dist/src/log-reporter.d.ts +18 -0
  56. package/dist/src/log-reporter.js +16 -0
  57. package/dist/src/native-fusion/parsers.d.ts +12 -0
  58. package/dist/src/native-fusion/parsers.js +687 -0
  59. package/dist/src/native-fusion/service.d.ts +25 -0
  60. package/dist/src/native-fusion/service.js +176 -0
  61. package/dist/src/native-fusion/state.d.ts +3 -0
  62. package/dist/src/native-fusion/state.js +22 -0
  63. package/dist/src/native-fusion/types.d.ts +24 -0
  64. package/dist/src/native-fusion/types.js +1 -0
  65. package/dist/src/region.d.ts +15 -0
  66. package/dist/src/region.js +99 -0
  67. package/dist/src/relay/client.d.ts +62 -0
  68. package/dist/src/relay/client.js +311 -0
  69. package/dist/src/session/handlers/agents.d.ts +4 -0
  70. package/dist/src/session/handlers/agents.js +55 -0
  71. package/dist/src/session/handlers/chat.d.ts +4 -0
  72. package/dist/src/session/handlers/chat.js +326 -0
  73. package/dist/src/session/handlers/control.d.ts +5 -0
  74. package/dist/src/session/handlers/control.js +57 -0
  75. package/dist/src/session/handlers/fs.d.ts +10 -0
  76. package/dist/src/session/handlers/fs.js +256 -0
  77. package/dist/src/session/manager.d.ts +28 -0
  78. package/dist/src/session/manager.js +174 -0
  79. package/dist/src/session/store.d.ts +7 -0
  80. package/dist/src/session/store.js +46 -0
  81. package/dist/src/session/types.d.ts +35 -0
  82. package/dist/src/session/types.js +4 -0
  83. package/dist/src/upgrade/engine.d.ts +65 -0
  84. package/dist/src/upgrade/engine.js +239 -0
  85. package/package.json +2 -2
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ import '../src/index.js';
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ import '../src/index.js';
@@ -0,0 +1,35 @@
1
+ import { EventEmitter } from 'node:events';
2
+ import type { AgentType } from '@shennian/wire';
3
+ export type AgentEvent = {
4
+ state: string;
5
+ runId: string;
6
+ seq: number;
7
+ text?: string;
8
+ thinking?: boolean;
9
+ name?: string;
10
+ args?: Record<string, unknown>;
11
+ result?: string;
12
+ message?: string;
13
+ usage?: {
14
+ inputTokens: number;
15
+ outputTokens: number;
16
+ };
17
+ title?: string;
18
+ source?: string;
19
+ agentSessionId?: string;
20
+ };
21
+ export interface AgentAdapterEvents {
22
+ agentEvent: [event: AgentEvent];
23
+ error: [error: Error];
24
+ }
25
+ export declare abstract class AgentAdapter extends EventEmitter<AgentAdapterEvents> {
26
+ abstract readonly type: AgentType;
27
+ abstract start(sessionId: string, workDir: string, agentSessionId?: string | null): Promise<void>;
28
+ abstract send(text: string, modelId?: string): Promise<void>;
29
+ abstract resume(agentSessionId: string): Promise<void>;
30
+ abstract stop(): Promise<void>;
31
+ }
32
+ export declare function registerAgent(type: AgentType, factory: () => AgentAdapter): void;
33
+ export declare function unregisterAgent(type: AgentType): void;
34
+ export declare function createAgent(type: AgentType): AgentAdapter | null;
35
+ export declare function getRegisteredAgents(): AgentType[];
@@ -0,0 +1,19 @@
1
+ // @arch docs/architecture/cli/agent-adapters.md
2
+ // @test src/__tests__/agents-e2e.ts
3
+ import { EventEmitter } from 'node:events';
4
+ export class AgentAdapter extends EventEmitter {
5
+ }
6
+ const registry = new Map();
7
+ export function registerAgent(type, factory) {
8
+ registry.set(type, factory);
9
+ }
10
+ export function unregisterAgent(type) {
11
+ registry.delete(type);
12
+ }
13
+ export function createAgent(type) {
14
+ const factory = registry.get(type);
15
+ return factory ? factory() : null;
16
+ }
17
+ export function getRegisteredAgents() {
18
+ return [...registry.keys()];
19
+ }
@@ -0,0 +1,25 @@
1
+ import { AgentAdapter } from './adapter.js';
2
+ export declare function normalizeClaudeModelId(modelId?: string | null): string;
3
+ export declare class ClaudeAdapter extends AgentAdapter {
4
+ readonly type: "claude";
5
+ private process;
6
+ private agentSessionId;
7
+ private sessionId;
8
+ private workDir;
9
+ private seq;
10
+ private runId;
11
+ private hasEmittedText;
12
+ private terminalState;
13
+ start(sessionId: string, workDir: string, agentSessionId?: string | null): Promise<void>;
14
+ send(text: string, modelId?: string): Promise<void>;
15
+ resume(agentSessionId: string): Promise<void>;
16
+ stop(): Promise<void>;
17
+ private spawnAndParse;
18
+ private handleStreamEvent;
19
+ private handleProcessClose;
20
+ private emitFinalIfOpen;
21
+ private emitErrorIfOpen;
22
+ private resetRunState;
23
+ private emitEvent;
24
+ private killProcess;
25
+ }
@@ -0,0 +1,234 @@
1
+ import { createInterface } from 'node:readline';
2
+ import { randomUUID } from 'node:crypto';
3
+ import { AgentAdapter, registerAgent } from './adapter.js';
4
+ import { resolveBuiltinCommand, spawnResolvedCommand } from './command-spec.js';
5
+ export function normalizeClaudeModelId(modelId) {
6
+ const trimmed = modelId?.trim();
7
+ return trimmed || 'default';
8
+ }
9
+ export class ClaudeAdapter extends AgentAdapter {
10
+ type = 'claude';
11
+ process = null;
12
+ agentSessionId = null;
13
+ sessionId = null;
14
+ workDir = null;
15
+ seq = 0;
16
+ runId = '';
17
+ hasEmittedText = false;
18
+ terminalState = 'open';
19
+ async start(sessionId, workDir, agentSessionId) {
20
+ this.sessionId = sessionId;
21
+ this.workDir = workDir;
22
+ this.seq = 0;
23
+ if (agentSessionId)
24
+ this.agentSessionId = agentSessionId;
25
+ }
26
+ async send(text, modelId) {
27
+ await this.killProcess();
28
+ this.runId = randomUUID();
29
+ this.resetRunState();
30
+ const args = ['-p', text, '--output-format', 'stream-json', '--verbose'];
31
+ if (process.getuid?.() !== 0) {
32
+ args.push('--dangerously-skip-permissions');
33
+ }
34
+ args.push('--model', normalizeClaudeModelId(modelId));
35
+ if (this.agentSessionId) {
36
+ args.push('--resume', this.agentSessionId);
37
+ }
38
+ this.spawnAndParse(args);
39
+ }
40
+ async resume(agentSessionId) {
41
+ await this.killProcess();
42
+ this.agentSessionId = agentSessionId;
43
+ this.runId = randomUUID();
44
+ this.resetRunState();
45
+ const resumeArgs = ['--resume', agentSessionId, '--output-format', 'stream-json', '--verbose'];
46
+ if (process.getuid?.() !== 0) {
47
+ resumeArgs.push('--dangerously-skip-permissions');
48
+ }
49
+ this.spawnAndParse(resumeArgs);
50
+ }
51
+ async stop() {
52
+ await this.killProcess();
53
+ }
54
+ spawnAndParse(args) {
55
+ const spec = resolveBuiltinCommand('claude');
56
+ if (!spec) {
57
+ this.emit('error', new Error('Command "claude" not found. Is Claude Code CLI installed?'));
58
+ return;
59
+ }
60
+ const proc = spawnResolvedCommand(spec, args, {
61
+ cwd: this.workDir ?? undefined,
62
+ stdio: ['ignore', 'pipe', 'pipe'],
63
+ env: { ...process.env },
64
+ });
65
+ this.process = proc;
66
+ const rl = createInterface({ input: proc.stdout });
67
+ rl.on('line', (line) => {
68
+ if (!line.trim())
69
+ return;
70
+ try {
71
+ const obj = JSON.parse(line);
72
+ this.handleStreamEvent(obj);
73
+ }
74
+ catch {
75
+ // skip malformed lines
76
+ }
77
+ });
78
+ let stderrBuf = '';
79
+ proc.stderr?.on('data', (chunk) => {
80
+ const text = chunk.toString();
81
+ stderrBuf += text;
82
+ if (this.terminalState !== 'open')
83
+ return;
84
+ // Stream stderr lines in real-time so the app shows errors/retries immediately
85
+ for (const line of text.split('\n')) {
86
+ const trimmed = line.trim();
87
+ if (trimmed) {
88
+ this.emitEvent({ state: 'delta', text: trimmed + '\n' });
89
+ }
90
+ }
91
+ });
92
+ proc.on('close', (code) => {
93
+ if (this.process !== proc)
94
+ return;
95
+ this.process = null;
96
+ this.handleProcessClose(code, stderrBuf);
97
+ });
98
+ proc.on('error', (err) => {
99
+ if (this.process !== proc)
100
+ return;
101
+ this.process = null;
102
+ if (err.code === 'ENOENT') {
103
+ this.emit('error', new Error('Command "claude" not found. Is Claude Code CLI installed?'));
104
+ }
105
+ else {
106
+ this.emit('error', err);
107
+ }
108
+ });
109
+ }
110
+ handleStreamEvent(obj) {
111
+ if (obj.type === 'system' && obj.subtype === 'init' && obj.session_id) {
112
+ this.agentSessionId = obj.session_id;
113
+ this.emitEvent({ state: 'start', agentSessionId: this.agentSessionId });
114
+ return;
115
+ }
116
+ if (obj.type === 'system' &&
117
+ obj.subtype === 'api_retry' &&
118
+ obj.error === 'authentication_failed') {
119
+ this.emitErrorIfOpen({
120
+ state: 'error',
121
+ message: 'Claude authentication failed. Run "claude auth login" and retry.',
122
+ });
123
+ return;
124
+ }
125
+ if (obj.type === 'assistant') {
126
+ // New format (claude >= 2.1): content is in message.content[]
127
+ if (obj.message?.content) {
128
+ for (const block of obj.message.content) {
129
+ if (block.type === 'text' && block.text) {
130
+ const prefix = this.hasEmittedText ? '\n\n' : '';
131
+ this.emitEvent({ state: 'delta', text: prefix + block.text });
132
+ this.hasEmittedText = true;
133
+ }
134
+ else if (block.type === 'thinking' && block.thinking) {
135
+ this.emitEvent({ state: 'delta', text: block.thinking, thinking: true });
136
+ }
137
+ else if (block.type === 'tool_use') {
138
+ this.emitEvent({ state: 'tool-call', name: block.name, args: block.input });
139
+ }
140
+ }
141
+ return;
142
+ }
143
+ // Legacy flat format (pre-2.1)
144
+ if (obj.subtype === 'text' && obj.text) {
145
+ const prefix = this.hasEmittedText ? '\n\n' : '';
146
+ this.emitEvent({ state: 'delta', text: prefix + obj.text });
147
+ this.hasEmittedText = true;
148
+ }
149
+ else if (obj.subtype === 'thinking' && obj.thinking) {
150
+ this.emitEvent({ state: 'delta', text: obj.thinking, thinking: true });
151
+ }
152
+ else if (obj.subtype === 'tool_use') {
153
+ this.emitEvent({ state: 'tool-call', name: obj.name, args: obj.input });
154
+ }
155
+ return;
156
+ }
157
+ if (obj.type === 'result') {
158
+ if (obj.subtype === 'tool_result') {
159
+ const content = typeof obj.content === 'string' ? obj.content : JSON.stringify(obj.content);
160
+ this.emitEvent({ state: 'tool-result', name: obj.name, result: content });
161
+ }
162
+ else if (obj.subtype === 'success') {
163
+ if (obj.session_id) {
164
+ this.agentSessionId = obj.session_id;
165
+ }
166
+ const usage = obj.usage ?? obj.message?.usage;
167
+ this.emitFinalIfOpen({
168
+ state: 'final',
169
+ agentSessionId: this.agentSessionId ?? undefined,
170
+ usage: usage
171
+ ? { inputTokens: usage.input_tokens, outputTokens: usage.output_tokens }
172
+ : undefined,
173
+ });
174
+ }
175
+ else if (obj.subtype === 'error') {
176
+ this.emitErrorIfOpen({
177
+ state: 'error',
178
+ message: obj.error ?? obj.result ?? 'unknown error',
179
+ });
180
+ }
181
+ }
182
+ }
183
+ handleProcessClose(code, stderrBuf) {
184
+ if (code !== 0 && code !== null) {
185
+ const msg = stderrBuf.trim() || `claude exited with code ${code}`;
186
+ this.emitErrorIfOpen({ state: 'error', message: msg });
187
+ return;
188
+ }
189
+ this.emitFinalIfOpen({
190
+ state: 'final',
191
+ agentSessionId: this.agentSessionId ?? undefined,
192
+ });
193
+ }
194
+ emitFinalIfOpen(partial) {
195
+ if (this.terminalState !== 'open')
196
+ return;
197
+ this.terminalState = 'final';
198
+ this.emitEvent(partial);
199
+ }
200
+ emitErrorIfOpen(partial) {
201
+ if (this.terminalState !== 'open')
202
+ return;
203
+ this.terminalState = 'error';
204
+ this.emitEvent(partial);
205
+ }
206
+ resetRunState() {
207
+ this.seq = 0;
208
+ this.hasEmittedText = false;
209
+ this.terminalState = 'open';
210
+ }
211
+ emitEvent(partial) {
212
+ const event = {
213
+ ...partial,
214
+ runId: this.runId,
215
+ seq: this.seq++,
216
+ };
217
+ this.emit('agentEvent', event);
218
+ }
219
+ async killProcess() {
220
+ const proc = this.process;
221
+ if (!proc)
222
+ return;
223
+ this.process = null;
224
+ proc.kill('SIGTERM');
225
+ await new Promise((resolve) => {
226
+ proc.on('close', resolve);
227
+ setTimeout(() => {
228
+ proc.kill('SIGKILL');
229
+ resolve();
230
+ }, 3000);
231
+ });
232
+ }
233
+ }
234
+ registerAgent('claude', () => new ClaudeAdapter());
@@ -0,0 +1,52 @@
1
+ import { AgentAdapter } from './adapter.js';
2
+ export declare class CodexAdapter extends AgentAdapter {
3
+ readonly type: "codex";
4
+ private process;
5
+ private workDir;
6
+ private seq;
7
+ private runId;
8
+ private pendingUsage;
9
+ private agentSessionId;
10
+ private hasEmittedText;
11
+ private textTail;
12
+ private terminalState;
13
+ private forceCloseTimer;
14
+ private stderrBuf;
15
+ private rpcSeq;
16
+ private pendingRequests;
17
+ private appServerReady;
18
+ private appServerStartupError;
19
+ private activeTurnId;
20
+ private namedThread;
21
+ private deltaItemIds;
22
+ private lastTransientStatus;
23
+ start(_sessionId: string, workDir: string, agentSessionId?: string | null): Promise<void>;
24
+ send(text: string, modelId?: string): Promise<void>;
25
+ resume(agentSessionId: string): Promise<void>;
26
+ stop(): Promise<void>;
27
+ private spawnCodex;
28
+ private spawnAppServer;
29
+ private ensureAppServer;
30
+ private initializeAppServer;
31
+ private sendRpc;
32
+ private handleAppServerMessage;
33
+ private handleAppServerNonJsonStdout;
34
+ private failAppServerStartup;
35
+ private handleAppServerCompletedItem;
36
+ private handleAppServerUsage;
37
+ private handleCodexItemLine;
38
+ private handleStreamEvent;
39
+ private emitEvent;
40
+ private killProcess;
41
+ private rejectAllPending;
42
+ private handleProcessClose;
43
+ private emitFinalIfOpen;
44
+ private emitErrorIfOpen;
45
+ private resetRunState;
46
+ private emitTransientStatus;
47
+ private resetTextState;
48
+ private emitText;
49
+ private scheduleProcessClose;
50
+ private clearForceCloseTimer;
51
+ }
52
+ export declare function normalizeCodexModelId(modelId?: string | null): string | undefined;