engine7 7.0.0
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 +55 -0
- package/bin/engine7 +2 -0
- package/bin/engine7.cmd +2 -0
- package/dist/cli.mjs +424 -0
- package/dist/engine-startup.mjs +45923 -0
- package/dist/main.mjs +46066 -0
- package/package.json +49 -0
- package/templates/_platform.md +32 -0
- package/templates/coding.md +75 -0
- package/templates/config.template.json +233 -0
- package/templates/workspace/AGENTS.md +56 -0
- package/templates/workspace/HEARTBEAT.md +42 -0
- package/templates/workspace/SESSION-STATE.md +15 -0
- package/templates/workspace/SOUL.md +18 -0
- package/templates/workspace/prompts/contacts.md +50 -0
package/README.md
ADDED
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
# Engine 7
|
|
2
|
+
|
|
3
|
+
Self-hosted AI agent engine with multi-platform support (Discord/Feishu/WeChat), persistent memory, calendar, and voice chat.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- 🤖 Multi-LLM provider support (Anthropic/OpenAI/Gemini compatible)
|
|
8
|
+
- 💾 Persistent memory system with semantic search
|
|
9
|
+
- 📅 Calendar with task management and reminders
|
|
10
|
+
- 🎤 Voice chat integration (WebRTC + TTS)
|
|
11
|
+
- 🔄 Cron jobs and background tasks
|
|
12
|
+
- 🌐 Cross-platform (Windows/Linux/macOS)
|
|
13
|
+
|
|
14
|
+
## Requirements
|
|
15
|
+
|
|
16
|
+
- Node.js >= 22
|
|
17
|
+
|
|
18
|
+
## Installation
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
npm install -g engine7
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
## Quick Start
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
engine7 init
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
This creates a workspace with templates for:
|
|
31
|
+
- Agent configuration (SOUL.md, AGENTS.md)
|
|
32
|
+
- Memory system (MEMORY.md, topics/)
|
|
33
|
+
- Session state tracking (SESSION-STATE.md)
|
|
34
|
+
- Heartbeat automation (HEARTBEAT.md)
|
|
35
|
+
|
|
36
|
+
## Development
|
|
37
|
+
|
|
38
|
+
```bash
|
|
39
|
+
# Build bundles
|
|
40
|
+
npm run build
|
|
41
|
+
|
|
42
|
+
# Start engine
|
|
43
|
+
npm start
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
## Architecture
|
|
47
|
+
|
|
48
|
+
- **Bundled with esbuild**: Three entry points (main, cli, engine-startup)
|
|
49
|
+
- **ESM native**: Modern JavaScript modules
|
|
50
|
+
- **SQLite storage**: Persistent sessions and memory
|
|
51
|
+
- **Plugin system**: Extendable tools and providers
|
|
52
|
+
|
|
53
|
+
## License
|
|
54
|
+
|
|
55
|
+
MIT
|
package/bin/engine7
ADDED
package/bin/engine7.cmd
ADDED
package/dist/cli.mjs
ADDED
|
@@ -0,0 +1,424 @@
|
|
|
1
|
+
// src/cli-init.ts
|
|
2
|
+
import * as path from "node:path";
|
|
3
|
+
import * as fs from "node:fs";
|
|
4
|
+
import * as readline from "node:readline";
|
|
5
|
+
import { fileURLToPath } from "node:url";
|
|
6
|
+
var __filename = fileURLToPath(import.meta.url);
|
|
7
|
+
var __dirname = path.dirname(__filename);
|
|
8
|
+
var SCHEMA_VERSION = 1;
|
|
9
|
+
function parseArgs() {
|
|
10
|
+
const args = process.argv.slice(2);
|
|
11
|
+
let stateDir = "";
|
|
12
|
+
let quick = false;
|
|
13
|
+
let dryRun2 = false;
|
|
14
|
+
let startIdx = 0;
|
|
15
|
+
if (args[0] === "init") startIdx = 1;
|
|
16
|
+
for (let i = startIdx; i < args.length; i++) {
|
|
17
|
+
if (args[i] === "--state-dir" && args[i + 1]) {
|
|
18
|
+
stateDir = args[++i];
|
|
19
|
+
} else if (args[i] === "--quick") {
|
|
20
|
+
quick = true;
|
|
21
|
+
} else if (args[i] === "--dry-run") {
|
|
22
|
+
dryRun2 = true;
|
|
23
|
+
} else if (args[i] === "--help" || args[i] === "-h") {
|
|
24
|
+
printHelp();
|
|
25
|
+
process.exit(0);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
if (!stateDir) {
|
|
29
|
+
console.error("\u274C \u7F3A\u5C11 --state-dir \u53C2\u6570");
|
|
30
|
+
console.error(" \u7528\u6CD5: engine7 init --state-dir <path>");
|
|
31
|
+
process.exit(1);
|
|
32
|
+
}
|
|
33
|
+
stateDir = path.resolve(stateDir);
|
|
34
|
+
return { stateDir, quick, dryRun: dryRun2 };
|
|
35
|
+
}
|
|
36
|
+
function printHelp() {
|
|
37
|
+
console.log(`
|
|
38
|
+
engine7 init \u2014 \u521D\u59CB\u5316 agent \u5DE5\u4F5C\u76EE\u5F55
|
|
39
|
+
|
|
40
|
+
\u7528\u6CD5:
|
|
41
|
+
engine7 init --state-dir <path> [\u9009\u9879]
|
|
42
|
+
|
|
43
|
+
\u9009\u9879:
|
|
44
|
+
--state-dir <path> agent \u6839\u76EE\u5F55\uFF08\u5FC5\u586B\uFF0C\u652F\u6301\u76F8\u5BF9\u8DEF\u5F84\uFF09
|
|
45
|
+
--quick \u7528\u9ED8\u8BA4\u914D\u7F6E\u8DF3\u8FC7\u4EA4\u4E92
|
|
46
|
+
--dry-run \u53EA\u663E\u793A\u4F1A\u521B\u5EFA\u4EC0\u4E48\uFF0C\u4E0D\u5B9E\u9645\u521B\u5EFA
|
|
47
|
+
-h, --help \u663E\u793A\u5E2E\u52A9
|
|
48
|
+
|
|
49
|
+
\u793A\u4F8B:
|
|
50
|
+
engine7 init --state-dir D:/my-agent
|
|
51
|
+
engine7 init --state-dir ./my-agent --quick
|
|
52
|
+
engine7 init --state-dir D:/my-agent --dry-run
|
|
53
|
+
`);
|
|
54
|
+
}
|
|
55
|
+
function createReadline() {
|
|
56
|
+
return readline.createInterface({
|
|
57
|
+
input: process.stdin,
|
|
58
|
+
output: process.stdout
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
async function ask(rl, question, defaultValue) {
|
|
62
|
+
const prompt = defaultValue ? `${question} [${defaultValue}]: ` : `${question}: `;
|
|
63
|
+
return new Promise((resolve2) => {
|
|
64
|
+
rl.question(prompt, (answer) => {
|
|
65
|
+
resolve2(answer.trim() || defaultValue || "");
|
|
66
|
+
});
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
async function askChoice(rl, question, choices, defaultIdx = 0) {
|
|
70
|
+
console.log(question);
|
|
71
|
+
choices.forEach((c, i) => console.log(` ${i + 1}. ${c}`));
|
|
72
|
+
const answer = await ask(rl, `\u9009\u62E9 (1-${choices.length})`, String(defaultIdx + 1));
|
|
73
|
+
const idx = parseInt(answer, 10) - 1;
|
|
74
|
+
return choices[idx >= 0 && idx < choices.length ? idx : defaultIdx];
|
|
75
|
+
}
|
|
76
|
+
function getDefaultValues(stateDir) {
|
|
77
|
+
return {
|
|
78
|
+
stateDir,
|
|
79
|
+
agentName: "Agent",
|
|
80
|
+
primaryProvider: "dashscope",
|
|
81
|
+
primaryApiKey: "",
|
|
82
|
+
primaryModel: "dashscope/qwen3.7-max",
|
|
83
|
+
visionModel: "dashscope/qwen3.7-max",
|
|
84
|
+
discordEnabled: false,
|
|
85
|
+
discordToken: "",
|
|
86
|
+
discordUserId: "",
|
|
87
|
+
feishuEnabled: false,
|
|
88
|
+
feishuAppId: "",
|
|
89
|
+
feishuAppSecret: "",
|
|
90
|
+
feishuOpenId: "",
|
|
91
|
+
apiPort: 16990
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
async function interactiveConfig(rl, defaults) {
|
|
95
|
+
const v = { ...defaults };
|
|
96
|
+
console.log("\n=== \u7B2C\u4E00\u6B65\uFF1A\u5FC5\u586B\u914D\u7F6E ===\n");
|
|
97
|
+
v.agentName = await ask(rl, "Agent \u540D\u79F0", defaults.agentName);
|
|
98
|
+
const providers = ["dashscope (\u901A\u4E49\u5343\u95EE)", "minimax (MiniMax)", "zhipu (\u667A\u8C31)", "deepseek (DeepSeek)"];
|
|
99
|
+
const providerMap = {
|
|
100
|
+
"dashscope (\u901A\u4E49\u5343\u95EE)": "dashscope",
|
|
101
|
+
"minimax (MiniMax)": "minimax",
|
|
102
|
+
"zhipu (\u667A\u8C31)": "zhipu",
|
|
103
|
+
"deepseek (DeepSeek)": "deepseek"
|
|
104
|
+
};
|
|
105
|
+
const chosenProvider = await askChoice(rl, "\u4E3B\u6A21\u578B Provider:", providers, 0);
|
|
106
|
+
v.primaryProvider = providerMap[chosenProvider] || "dashscope";
|
|
107
|
+
const keyMap = {
|
|
108
|
+
dashscope: "DashScope API Key",
|
|
109
|
+
minimax: "MiniMax API Key",
|
|
110
|
+
zhipu: "\u667A\u8C31 API Key",
|
|
111
|
+
deepseek: "DeepSeek API Key"
|
|
112
|
+
};
|
|
113
|
+
v.primaryApiKey = await ask(rl, keyMap[v.primaryProvider] || "API Key");
|
|
114
|
+
const modelMap = {
|
|
115
|
+
dashscope: ["dashscope/qwen3.7-max", "dashscope/qwen3.7-plus"],
|
|
116
|
+
minimax: ["minimax/MiniMax-M3", "minimax/MiniMax-M2.7"],
|
|
117
|
+
zhipu: ["zhipu/glm-5.1", "zhipu/glm-5v-turbo"],
|
|
118
|
+
deepseek: ["deepseek/deepseek-v4-pro", "deepseek/deepseek-v4-flash"]
|
|
119
|
+
};
|
|
120
|
+
const models = modelMap[v.primaryProvider] || ["dashscope/qwen3.7-max"];
|
|
121
|
+
v.primaryModel = await askChoice(rl, "\u4E3B\u6A21\u578B:", models, 0);
|
|
122
|
+
v.visionModel = v.primaryModel;
|
|
123
|
+
console.log("\n=== \u7B2C\u4E8C\u6B65\uFF1A\u53EF\u9009\u914D\u7F6E\uFF08\u56DE\u8F66\u8DF3\u8FC7\uFF09===\n");
|
|
124
|
+
const discordAns = await ask(rl, "\u542F\u7528 Discord? (y/n)", "n");
|
|
125
|
+
v.discordEnabled = discordAns.toLowerCase() === "y";
|
|
126
|
+
if (v.discordEnabled) {
|
|
127
|
+
v.discordToken = await ask(rl, "Discord Bot Token");
|
|
128
|
+
v.discordUserId = await ask(rl, "\u4F60\u7684 Discord User ID");
|
|
129
|
+
}
|
|
130
|
+
const feishuAns = await ask(rl, "\u542F\u7528\u98DE\u4E66? (y/n)", "n");
|
|
131
|
+
v.feishuEnabled = feishuAns.toLowerCase() === "y";
|
|
132
|
+
if (v.feishuEnabled) {
|
|
133
|
+
v.feishuAppId = await ask(rl, "\u98DE\u4E66 App ID");
|
|
134
|
+
v.feishuAppSecret = await ask(rl, "\u98DE\u4E66 App Secret");
|
|
135
|
+
v.feishuOpenId = await ask(rl, "\u4F60\u7684\u98DE\u4E66 open_id");
|
|
136
|
+
}
|
|
137
|
+
const portAns = await ask(rl, "API \u7AEF\u53E3", String(defaults.apiPort));
|
|
138
|
+
v.apiPort = parseInt(portAns, 10) || defaults.apiPort;
|
|
139
|
+
return v;
|
|
140
|
+
}
|
|
141
|
+
function generateConfig(v) {
|
|
142
|
+
const workspace = path.join(v.stateDir, "workspace").replace(/\\/g, "/");
|
|
143
|
+
const config = {
|
|
144
|
+
schemaVersion: SCHEMA_VERSION,
|
|
145
|
+
stateDir: v.stateDir.replace(/\\/g, "/"),
|
|
146
|
+
mediaDir: `${v.stateDir.replace(/\\/g, "/")}/media/inbound`,
|
|
147
|
+
models: {
|
|
148
|
+
providers: {}
|
|
149
|
+
},
|
|
150
|
+
tools: {},
|
|
151
|
+
session: { dmScope: "main", groupScope: "main" },
|
|
152
|
+
sandbox: { mode: "off" },
|
|
153
|
+
display: {
|
|
154
|
+
thinking: { enabled: false, emoji: "\u{1F4AD}", maxLen: 300 },
|
|
155
|
+
toolUse: { enabled: true, emoji: "\u{1F527}", displayMode: "raw", bashDisplayMode: "both" },
|
|
156
|
+
toolResult: { enabled: false },
|
|
157
|
+
reactions: { enabled: true, start: "\u{1F440}", done: "\u2705", error: "\u274C" },
|
|
158
|
+
preview: { enabled: true, agentName: v.agentName, color: "orange" },
|
|
159
|
+
typing: { enabled: true }
|
|
160
|
+
},
|
|
161
|
+
agents: {
|
|
162
|
+
defaults: {
|
|
163
|
+
workspace,
|
|
164
|
+
name: v.agentName,
|
|
165
|
+
model: {
|
|
166
|
+
primary: v.primaryModel,
|
|
167
|
+
vision: v.visionModel
|
|
168
|
+
},
|
|
169
|
+
features: {
|
|
170
|
+
filesystem: true,
|
|
171
|
+
shell: true,
|
|
172
|
+
webSearch: true,
|
|
173
|
+
webFetch: true,
|
|
174
|
+
memory: true,
|
|
175
|
+
topics: true,
|
|
176
|
+
"topic-extract": true,
|
|
177
|
+
"topic-recall": true,
|
|
178
|
+
cron: true,
|
|
179
|
+
agent: true,
|
|
180
|
+
agentTeams: true,
|
|
181
|
+
processOutput: "minimal",
|
|
182
|
+
interrupt: "command",
|
|
183
|
+
debounceMs: 5e3
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
},
|
|
187
|
+
channels: {
|
|
188
|
+
discord: {
|
|
189
|
+
enabled: v.discordEnabled,
|
|
190
|
+
dmPolicy: "pairing",
|
|
191
|
+
groupPolicy: "open",
|
|
192
|
+
accounts: { default: { token: v.discordToken } },
|
|
193
|
+
replyToMode: "all"
|
|
194
|
+
},
|
|
195
|
+
feishu: {
|
|
196
|
+
enabled: v.feishuEnabled,
|
|
197
|
+
appId: v.feishuAppId,
|
|
198
|
+
appSecret: v.feishuAppSecret,
|
|
199
|
+
connectionMode: "websocket",
|
|
200
|
+
dmPolicy: "pairing",
|
|
201
|
+
groupPolicy: "open"
|
|
202
|
+
}
|
|
203
|
+
},
|
|
204
|
+
api: { port: v.apiPort },
|
|
205
|
+
prompt: {
|
|
206
|
+
mode: "custom",
|
|
207
|
+
staticFiles: ["AGENTS.md", "USER.md", "MEMORY.md"],
|
|
208
|
+
order: ["soul", "AGENTS.md", "using-tools", "USER.md", "MEMORY.md", "auto-memory-instructions"]
|
|
209
|
+
},
|
|
210
|
+
compaction: {
|
|
211
|
+
enabled: true,
|
|
212
|
+
bufferTokens: 23e3,
|
|
213
|
+
maxOutputTokens: 16384,
|
|
214
|
+
minReductionRatio: 0.3,
|
|
215
|
+
ruleBased: { enabled: true, essentialFields: [] },
|
|
216
|
+
memoryFlush: { enabled: true, forceFlushTranscriptBytes: "2.0mb" }
|
|
217
|
+
}
|
|
218
|
+
};
|
|
219
|
+
const providerDefs = {
|
|
220
|
+
dashscope: {
|
|
221
|
+
baseUrl: "https://dashscope.aliyuncs.com/compatible-mode/v1",
|
|
222
|
+
api: "openai-completions",
|
|
223
|
+
models: [
|
|
224
|
+
{ id: "qwen3.7-max", name: "Qwen 3.7 Max", reasoning: true, input: ["text"], contextWindow: 1e6, maxTokens: 65536 },
|
|
225
|
+
{ id: "qwen3.7-plus", name: "Qwen 3.7 Plus", reasoning: true, input: ["text", "image"], contextWindow: 1e6, maxTokens: 8192 }
|
|
226
|
+
]
|
|
227
|
+
},
|
|
228
|
+
minimax: {
|
|
229
|
+
baseUrl: "https://api.minimaxi.com/anthropic",
|
|
230
|
+
api: "anthropic",
|
|
231
|
+
models: [
|
|
232
|
+
{ id: "MiniMax-M3", name: "MiniMax M3", reasoning: true, input: ["text", "image"], contextWindow: 1e6, maxTokens: 64e3 },
|
|
233
|
+
{ id: "MiniMax-M2.7", name: "MiniMax M2.7", reasoning: true, input: ["text"], contextWindow: 204800, maxTokens: 64e3 }
|
|
234
|
+
]
|
|
235
|
+
},
|
|
236
|
+
zhipu: {
|
|
237
|
+
baseUrl: "https://open.bigmodel.cn/api/coding/paas/v4 ",
|
|
238
|
+
api: "openai-completions",
|
|
239
|
+
models: [
|
|
240
|
+
{ id: "glm-5.1", name: "GLM-5.1", reasoning: true, input: ["text"], contextWindow: 204800, maxTokens: 131072 },
|
|
241
|
+
{ id: "glm-5v-turbo", name: "GLM-5V-Turbo", reasoning: true, input: ["text", "image"], contextWindow: 2e5, maxTokens: 128e3 }
|
|
242
|
+
]
|
|
243
|
+
},
|
|
244
|
+
deepseek: {
|
|
245
|
+
baseUrl: "https://api.deepseek.com/anthropic",
|
|
246
|
+
api: "anthropic",
|
|
247
|
+
thinking: { enabled: true, budgetTokens: 8192 },
|
|
248
|
+
models: [
|
|
249
|
+
{ id: "deepseek-v4-pro", name: "DeepSeek V4 Pro", reasoning: true, input: ["text"], contextWindow: 1e6, maxTokens: 384e3 },
|
|
250
|
+
{ id: "deepseek-v4-flash", name: "DeepSeek V4 Flash", reasoning: true, input: ["text"], contextWindow: 1e6, maxTokens: 384e3 }
|
|
251
|
+
]
|
|
252
|
+
}
|
|
253
|
+
};
|
|
254
|
+
if (providerDefs[v.primaryProvider]) {
|
|
255
|
+
config.models.providers[v.primaryProvider] = {
|
|
256
|
+
...providerDefs[v.primaryProvider],
|
|
257
|
+
apiKey: v.primaryApiKey
|
|
258
|
+
};
|
|
259
|
+
}
|
|
260
|
+
return config;
|
|
261
|
+
}
|
|
262
|
+
function buildDirTree(v) {
|
|
263
|
+
const d = v.stateDir;
|
|
264
|
+
const w = path.join(d, "workspace");
|
|
265
|
+
const now = (/* @__PURE__ */ new Date()).toLocaleString("sv-SE", { timeZone: "Asia/Shanghai", hour12: false });
|
|
266
|
+
return [
|
|
267
|
+
// 目录
|
|
268
|
+
{ path: path.join(d, "configs"), type: "dir" },
|
|
269
|
+
{ path: path.join(d, "state", "agents", "main", "sessions"), type: "dir" },
|
|
270
|
+
{ path: path.join(w, "prompts"), type: "dir" },
|
|
271
|
+
{ path: path.join(w, "memory", "daily"), type: "dir" },
|
|
272
|
+
{ path: path.join(w, "docs", "research"), type: "dir" },
|
|
273
|
+
{ path: path.join(w, "docs", "todo"), type: "dir" },
|
|
274
|
+
{ path: path.join(w, "docs", "decisions"), type: "dir" },
|
|
275
|
+
{ path: path.join(w, "docs", "knowledge"), type: "dir" },
|
|
276
|
+
{ path: path.join(w, "docs", "sop"), type: "dir" },
|
|
277
|
+
{ path: path.join(d, "logs"), type: "dir" },
|
|
278
|
+
{ path: path.join(d, "media", "inbound"), type: "dir" },
|
|
279
|
+
// workspace 文件
|
|
280
|
+
{
|
|
281
|
+
path: path.join(w, "SESSION-STATE.md"),
|
|
282
|
+
type: "file",
|
|
283
|
+
content: readTemplate("workspace/SESSION-STATE.md").replace("{{CURRENT_TIME}}", now)
|
|
284
|
+
},
|
|
285
|
+
{ path: path.join(w, "HEARTBEAT.md"), type: "file", content: readTemplate("workspace/HEARTBEAT.md") },
|
|
286
|
+
{
|
|
287
|
+
path: path.join(w, "SOUL.md"),
|
|
288
|
+
type: "file",
|
|
289
|
+
content: readTemplate("workspace/SOUL.md").replace(/\{\{AGENT_NAME\}\}/g, v.agentName)
|
|
290
|
+
},
|
|
291
|
+
{ path: path.join(w, "AGENTS.md"), type: "file", content: readTemplate("workspace/AGENTS.md") },
|
|
292
|
+
{
|
|
293
|
+
path: path.join(w, "prompts", "contacts.md"),
|
|
294
|
+
type: "file",
|
|
295
|
+
content: readTemplate("workspace/prompts/contacts.md").replace("{{DISCORD_USER_ID}}", v.discordUserId || "YOUR_DISCORD_ID").replace("{{FEISHU_OPEN_ID}}", v.feishuOpenId || "YOUR_FEISHU_OPEN_ID")
|
|
296
|
+
},
|
|
297
|
+
{ path: path.join(w, "MEMORY.md"), type: "file", content: "# MEMORY.md \u2014 \u8BB0\u5FC6\u6587\u4EF6\u7D22\u5F15\n\n> \u6700\u540E\u66F4\u65B0\uFF1A\u521D\u59CB\u5316\n" },
|
|
298
|
+
{ path: path.join(w, "USER.md"), type: "file", content: "# USER.md \u2014 \u7528\u6237\u4FE1\u606F\n\n\uFF08\u5728\u8FD9\u91CC\u8BB0\u5F55\u7528\u6237\u7684\u504F\u597D\u3001\u80CC\u666F\u7B49\uFF09\n" },
|
|
299
|
+
// package.json — 让 agent 目录成为独立 npm 项目根,防止 npm hoisting
|
|
300
|
+
{
|
|
301
|
+
path: path.join(d, "package.json"),
|
|
302
|
+
type: "file",
|
|
303
|
+
content: JSON.stringify({
|
|
304
|
+
name: v.agentName.toLowerCase().replace(/[^a-z0-9-]/g, "-") || "agent",
|
|
305
|
+
version: "1.0.0",
|
|
306
|
+
private: true,
|
|
307
|
+
description: `Engine 7 agent: ${v.agentName}`
|
|
308
|
+
}, null, 2) + "\n"
|
|
309
|
+
},
|
|
310
|
+
// 启动脚本
|
|
311
|
+
{
|
|
312
|
+
path: path.join(d, "start.cmd"),
|
|
313
|
+
type: "file",
|
|
314
|
+
content: `@echo off
|
|
315
|
+
rem Engine 7 startup script
|
|
316
|
+
rem Auto-generated by engine7 init
|
|
317
|
+
|
|
318
|
+
cd /d "%~dp0"
|
|
319
|
+
|
|
320
|
+
echo [start] Killing existing engine for main7.json...
|
|
321
|
+
for %%F in ("configs\\main7.json") do set CONFIG_NAME=%%~nxF
|
|
322
|
+
powershell -Command "Get-WmiObject Win32_Process | Where-Object { $_.Name -eq 'node.exe' -and $_.CommandLine -like '*%CONFIG_NAME%*' -and $_.CommandLine -like '*dist*' } | ForEach-Object { Write-Host '[start] Killing PID' $_.ProcessId; Stop-Process -Id $_.ProcessId -Force }"
|
|
323
|
+
|
|
324
|
+
timeout /t 2 /nobreak >nul 2>&1
|
|
325
|
+
|
|
326
|
+
echo [start] Starting Engine 7...
|
|
327
|
+
echo [start] Config: configs\\main7.json
|
|
328
|
+
echo.
|
|
329
|
+
|
|
330
|
+
node node_modules/engine7/dist/main.mjs --engine-config configs/main7.json
|
|
331
|
+
|
|
332
|
+
if %ERRORLEVEL% NEQ 0 (
|
|
333
|
+
echo.
|
|
334
|
+
echo [start] Engine failed with error code: %ERRORLEVEL%
|
|
335
|
+
pause
|
|
336
|
+
)
|
|
337
|
+
`
|
|
338
|
+
}
|
|
339
|
+
];
|
|
340
|
+
}
|
|
341
|
+
function readTemplate(relativePath) {
|
|
342
|
+
const candidates = [
|
|
343
|
+
path.join(__dirname, "..", "templates", relativePath),
|
|
344
|
+
path.join(__dirname, "..", "..", "templates", relativePath),
|
|
345
|
+
path.join(process.cwd(), "templates", relativePath)
|
|
346
|
+
];
|
|
347
|
+
for (const p of candidates) {
|
|
348
|
+
if (fs.existsSync(p)) {
|
|
349
|
+
return fs.readFileSync(p, "utf-8");
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
throw new Error(`\u6A21\u677F\u6587\u4EF6\u4E0D\u5B58\u5728: ${relativePath}\uFF08\u627E\u4E86: ${candidates.join(", ")}\uFF09`);
|
|
353
|
+
}
|
|
354
|
+
function dryRun(entries) {
|
|
355
|
+
console.log("\n[dry-run] \u5C06\u8981\u521B\u5EFA\uFF1A\n");
|
|
356
|
+
for (const e of entries) {
|
|
357
|
+
const prefix = e.type === "dir" ? "\u{1F4C1}" : "\u{1F4C4}";
|
|
358
|
+
console.log(` ${prefix} ${e.path}`);
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
function execute(entries) {
|
|
362
|
+
for (const e of entries) {
|
|
363
|
+
if (e.type === "dir") {
|
|
364
|
+
fs.mkdirSync(e.path, { recursive: true });
|
|
365
|
+
console.log(` \u{1F4C1} ${e.path}`);
|
|
366
|
+
} else {
|
|
367
|
+
fs.mkdirSync(path.dirname(e.path), { recursive: true });
|
|
368
|
+
fs.writeFileSync(e.path, e.content || "", "utf-8");
|
|
369
|
+
console.log(` \u{1F4C4} ${e.path}`);
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
}
|
|
373
|
+
async function main() {
|
|
374
|
+
const opts = parseArgs();
|
|
375
|
+
console.log(`
|
|
376
|
+
\u{1F680} engine7 init`);
|
|
377
|
+
console.log(` state-dir: ${opts.stateDir}`);
|
|
378
|
+
if (fs.existsSync(opts.stateDir) && !opts.dryRun) {
|
|
379
|
+
const files = fs.readdirSync(opts.stateDir);
|
|
380
|
+
if (files.length > 0) {
|
|
381
|
+
console.error(`
|
|
382
|
+
\u274C \u76EE\u5F55\u5DF2\u5B58\u5728\u4E14\u975E\u7A7A: ${opts.stateDir}`);
|
|
383
|
+
console.error(` \u8BF7\u9009\u62E9\u7A7A\u76EE\u5F55\u6216\u5148\u5220\u9664\u73B0\u6709\u5185\u5BB9`);
|
|
384
|
+
process.exit(1);
|
|
385
|
+
}
|
|
386
|
+
}
|
|
387
|
+
let values;
|
|
388
|
+
if (opts.quick) {
|
|
389
|
+
values = getDefaultValues(opts.stateDir);
|
|
390
|
+
console.log(" \u4F7F\u7528\u9ED8\u8BA4\u914D\u7F6E\uFF08--quick\uFF09");
|
|
391
|
+
} else {
|
|
392
|
+
const rl = createReadline();
|
|
393
|
+
values = await interactiveConfig(rl, getDefaultValues(opts.stateDir));
|
|
394
|
+
rl.close();
|
|
395
|
+
}
|
|
396
|
+
const config = generateConfig(values);
|
|
397
|
+
const configPath = path.join(opts.stateDir, "configs", "main7.json");
|
|
398
|
+
const tree = buildDirTree(values);
|
|
399
|
+
tree.push({
|
|
400
|
+
path: configPath,
|
|
401
|
+
type: "file",
|
|
402
|
+
content: JSON.stringify(config, null, 2)
|
|
403
|
+
});
|
|
404
|
+
if (opts.dryRun) {
|
|
405
|
+
dryRun(tree);
|
|
406
|
+
} else {
|
|
407
|
+
console.log("\n\u{1F4E6} \u6B63\u5728\u521B\u5EFA\u76EE\u5F55\u548C\u6587\u4EF6...\n");
|
|
408
|
+
execute(tree);
|
|
409
|
+
console.log(`
|
|
410
|
+
\u2705 \u521D\u59CB\u5316\u5B8C\u6210\uFF01
|
|
411
|
+
`);
|
|
412
|
+
console.log(`\u4E0B\u4E00\u6B65\uFF1A`);
|
|
413
|
+
console.log(` 1. \u68C0\u67E5\u5E76\u4FEE\u6539 ${opts.stateDir}/configs/main7.json`);
|
|
414
|
+
console.log(` 2. \u542F\u52A8 Engine: start.cmd ${configPath}`);
|
|
415
|
+
console.log(` 3. \u67E5\u770B workspace: ${path.join(opts.stateDir, "workspace")}`);
|
|
416
|
+
}
|
|
417
|
+
}
|
|
418
|
+
main().catch((err) => {
|
|
419
|
+
console.error(`
|
|
420
|
+
\u274C \u5931\u8D25: ${err.message}`);
|
|
421
|
+
console.error(err.stack);
|
|
422
|
+
process.exit(1);
|
|
423
|
+
});
|
|
424
|
+
//# sourceMappingURL=cli.mjs.map
|