nine-hundred 0.0.1
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 +43 -0
- package/dist/agent/config/index.js +85 -0
- package/dist/agent/context/compress.js +145 -0
- package/dist/agent/context/index.js +68 -0
- package/dist/agent/context/token.js +30 -0
- package/dist/agent/hooks/config.js +41 -0
- package/dist/agent/hooks/core.js +177 -0
- package/dist/agent/hooks/events/index.js +9 -0
- package/dist/agent/hooks/events/post-tool-use-hook.js +7 -0
- package/dist/agent/hooks/events/pre-tool-use-hook.js +8 -0
- package/dist/agent/hooks/events/session-start-hook.js +8 -0
- package/dist/agent/hooks/events/stop-hook.js +10 -0
- package/dist/agent/hooks/events/user-prompt-submit-hook.js +7 -0
- package/dist/agent/hooks/index.js +7 -0
- package/dist/agent/hooks/types.js +32 -0
- package/dist/agent/index.js +465 -0
- package/dist/agent/llm/index.js +35 -0
- package/dist/agent/mcp/client.js +87 -0
- package/dist/agent/mcp/config.js +51 -0
- package/dist/agent/mcp/index.js +90 -0
- package/dist/agent/mcp/schema.js +56 -0
- package/dist/agent/permission/exec.js +71 -0
- package/dist/agent/permission/network.js +37 -0
- package/dist/agent/permission/read.js +27 -0
- package/dist/agent/permission/util/command-changes-directory.js +29 -0
- package/dist/agent/permission/util/dangerous-path.json +116 -0
- package/dist/agent/permission/util/detect-dangerous-operation.js +230 -0
- package/dist/agent/permission/util/detect-language-interpreter.js +66 -0
- package/dist/agent/permission/util/detect-safe-command.js +61 -0
- package/dist/agent/permission/util/index.js +16 -0
- package/dist/agent/permission/util/is-dangerous-path.js +98 -0
- package/dist/agent/permission/util/is-inside-cwd.js +83 -0
- package/dist/agent/permission/util/is-safe-domains.js +47 -0
- package/dist/agent/permission/write.js +31 -0
- package/dist/agent/prompt/index.js +42 -0
- package/dist/agent/skills/planner/SKILL.md +90 -0
- package/dist/agent/skills/programmer-resume/SKILL.md +113 -0
- package/dist/agent/skills/skill-creator/LICENSE.txt +202 -0
- package/dist/agent/skills/skill-creator/SKILL.md +495 -0
- package/dist/agent/skills/skill-creator/agents/analyzer.md +274 -0
- package/dist/agent/skills/skill-creator/agents/comparator.md +202 -0
- package/dist/agent/skills/skill-creator/agents/grader.md +223 -0
- package/dist/agent/skills/skill-creator/assets/eval_review.html +146 -0
- package/dist/agent/skills/skill-creator/eval-viewer/generate_review.py +471 -0
- package/dist/agent/skills/skill-creator/eval-viewer/viewer.html +1325 -0
- package/dist/agent/skills/skill-creator/references/schemas.md +430 -0
- package/dist/agent/skills/skill-creator/scripts/__init__.py +0 -0
- package/dist/agent/skills/skill-creator/scripts/aggregate_benchmark.py +401 -0
- package/dist/agent/skills/skill-creator/scripts/generate_report.py +326 -0
- package/dist/agent/skills/skill-creator/scripts/improve_description.py +247 -0
- package/dist/agent/skills/skill-creator/scripts/package_skill.py +136 -0
- package/dist/agent/skills/skill-creator/scripts/quick_validate.py +103 -0
- package/dist/agent/skills/skill-creator/scripts/run_eval.py +310 -0
- package/dist/agent/skills/skill-creator/scripts/run_loop.py +328 -0
- package/dist/agent/skills/skill-creator/scripts/utils.py +47 -0
- package/dist/agent/skills.js +129 -0
- package/dist/agent/tools/agent_tool/agent_tool.test.js +64 -0
- package/dist/agent/tools/agent_tool/index.js +33 -0
- package/dist/agent/tools/exec_tool/exec_tool.test.js +48 -0
- package/dist/agent/tools/exec_tool/index.js +44 -0
- package/dist/agent/tools/load_skill_tool/index.js +5 -0
- package/dist/agent/tools/load_skill_tool/load_skill_tool.test.js +122 -0
- package/dist/agent/tools/memory_create_tool/index.js +8 -0
- package/dist/agent/tools/memory_create_tool/memory_create_tool.test.js +54 -0
- package/dist/agent/tools/memory_delete_tool/index.js +10 -0
- package/dist/agent/tools/memory_delete_tool/memory_delete_tool.test.js +39 -0
- package/dist/agent/tools/memory_retrieve_tool/index.js +61 -0
- package/dist/agent/tools/memory_retrieve_tool/memory_retrieve_tool.test.js +102 -0
- package/dist/agent/tools/profile_update_tool/index.js +30 -0
- package/dist/agent/tools/profile_update_tool/profile_update_tool.test.js +49 -0
- package/dist/agent/tools/read_file_tool/index.js +24 -0
- package/dist/agent/tools/read_file_tool/read_file_tool.test.js +43 -0
- package/dist/agent/tools/run_js_tool/index.js +48 -0
- package/dist/agent/tools/run_js_tool/run_js_tool.test.js +67 -0
- package/dist/agent/tools/run_py_tool/index.js +48 -0
- package/dist/agent/tools/run_py_tool/run_py_tool.test.js +67 -0
- package/dist/agent/tools/tool_logger.js +16 -0
- package/dist/agent/tools/tool_logger.test.js +22 -0
- package/dist/agent/tools/web_fetch_url/index.js +76 -0
- package/dist/agent/tools/web_fetch_url/web_fetch_url.test.js +102 -0
- package/dist/agent/tools/web_search_tool/index.js +26 -0
- package/dist/agent/tools/web_search_tool/web_search_tool.test.js +61 -0
- package/dist/agent/tools/write_file_tool/index.js +22 -0
- package/dist/agent/tools/write_file_tool/write_file_tool.test.js +46 -0
- package/dist/agent/tools.js +218 -0
- package/dist/cli/command/compact/index.js +14 -0
- package/dist/cli/command/index.js +62 -0
- package/dist/cli/command/invalid/index.js +4 -0
- package/dist/cli/command/new/chat-session.js +10 -0
- package/dist/cli/command/new/index.js +8 -0
- package/dist/cli/command/rewind/index.js +19 -0
- package/dist/cli/command/rewind/rewind-command.test.js +22 -0
- package/dist/cli/command/session/format.js +32 -0
- package/dist/cli/command/session/index.js +32 -0
- package/dist/cli/command/session/session-command.test.js +49 -0
- package/dist/cli/command/unknown/index.js +4 -0
- package/dist/cli/index.js +144 -0
- package/dist/db/checkpointer.js +15 -0
- package/dist/db/index.js +2 -0
- package/dist/db/path.js +8 -0
- package/dist/db/sessions.js +81 -0
- package/dist/db/tables/memory.js +12 -0
- package/dist/db/tables/memory_fts.js +29 -0
- package/dist/index.js +87 -0
- package/dist/install.js +154 -0
- package/package.json +51 -0
- package/pnpm-workspace.yaml +3 -0
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import { DatabaseSync } from 'node:sqlite';
|
|
2
|
+
import * as fs from 'node:fs';
|
|
3
|
+
import { CHECKPOINT_DB_PATH, ensureDataDir } from './path.js';
|
|
4
|
+
const RECENT_LIMIT = 20;
|
|
5
|
+
const RECENT_SESSIONS_QUERY = `
|
|
6
|
+
WITH ranked AS (
|
|
7
|
+
SELECT
|
|
8
|
+
c.thread_id,
|
|
9
|
+
json_extract(CAST(c.checkpoint AS TEXT), '$.ts') AS ts,
|
|
10
|
+
CAST(w.value AS TEXT) AS msg,
|
|
11
|
+
ROW_NUMBER() OVER (
|
|
12
|
+
PARTITION BY c.thread_id
|
|
13
|
+
ORDER BY json_extract(CAST(c.checkpoint AS TEXT), '$.ts') DESC
|
|
14
|
+
) AS rn
|
|
15
|
+
FROM checkpoints c
|
|
16
|
+
JOIN writes w
|
|
17
|
+
ON w.thread_id = c.thread_id
|
|
18
|
+
AND w.checkpoint_id = c.checkpoint_id
|
|
19
|
+
AND w.channel = 'messages'
|
|
20
|
+
AND w.idx = 0
|
|
21
|
+
WHERE json_extract(CAST(c.metadata AS TEXT), '$.source') = 'input'
|
|
22
|
+
)
|
|
23
|
+
SELECT thread_id, ts, msg
|
|
24
|
+
FROM ranked
|
|
25
|
+
WHERE rn = 1
|
|
26
|
+
ORDER BY ts DESC
|
|
27
|
+
LIMIT ?;
|
|
28
|
+
`;
|
|
29
|
+
function extractUserContent(rawMsg) {
|
|
30
|
+
try {
|
|
31
|
+
const parsed = JSON.parse(rawMsg);
|
|
32
|
+
if (!Array.isArray(parsed))
|
|
33
|
+
return '';
|
|
34
|
+
// LangGraph writes 表中 messages channel 的值是 lc 序列化格式数组,
|
|
35
|
+
// 每个元素形如 { id: ['langchain_core', 'messages', 'HumanMessage'], kwargs: { content: '...' } }
|
|
36
|
+
const humanMsg = parsed.find((m) => Array.isArray(m.id) && m.id.some((s) => s.includes('HumanMessage')));
|
|
37
|
+
if (!humanMsg)
|
|
38
|
+
return '';
|
|
39
|
+
const content = humanMsg.kwargs?.content;
|
|
40
|
+
if (typeof content === 'string')
|
|
41
|
+
return content;
|
|
42
|
+
if (Array.isArray(content)) {
|
|
43
|
+
const textPart = content.find((p) => typeof p === 'object' && p !== null && 'text' in p && typeof p.text === 'string');
|
|
44
|
+
return textPart?.text ?? '';
|
|
45
|
+
}
|
|
46
|
+
return '';
|
|
47
|
+
}
|
|
48
|
+
catch {
|
|
49
|
+
return '';
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
export function fetchRecentSessions() {
|
|
53
|
+
ensureDataDir();
|
|
54
|
+
if (!fs.existsSync(CHECKPOINT_DB_PATH))
|
|
55
|
+
return [];
|
|
56
|
+
const db = new DatabaseSync(CHECKPOINT_DB_PATH, { readOnly: true });
|
|
57
|
+
try {
|
|
58
|
+
const rows = db.prepare(RECENT_SESSIONS_QUERY).all(RECENT_LIMIT);
|
|
59
|
+
return rows.map((r) => ({
|
|
60
|
+
threadId: r.thread_id,
|
|
61
|
+
ts: r.ts,
|
|
62
|
+
lastUserInput: extractUserContent(r.msg),
|
|
63
|
+
}));
|
|
64
|
+
}
|
|
65
|
+
finally {
|
|
66
|
+
db.close();
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
export function threadExists(threadId) {
|
|
70
|
+
ensureDataDir();
|
|
71
|
+
if (!fs.existsSync(CHECKPOINT_DB_PATH))
|
|
72
|
+
return false;
|
|
73
|
+
const db = new DatabaseSync(CHECKPOINT_DB_PATH, { readOnly: true });
|
|
74
|
+
try {
|
|
75
|
+
const row = db.prepare('SELECT 1 FROM checkpoints WHERE thread_id = ? LIMIT 1').get(threadId);
|
|
76
|
+
return row !== undefined;
|
|
77
|
+
}
|
|
78
|
+
finally {
|
|
79
|
+
db.close();
|
|
80
|
+
}
|
|
81
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export const MEMORY_TABLE_SQL = `
|
|
2
|
+
CREATE TABLE IF NOT EXISTS memory (
|
|
3
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
4
|
+
type TEXT NOT NULL,
|
|
5
|
+
content TEXT NOT NULL,
|
|
6
|
+
keywords TEXT,
|
|
7
|
+
importance INTEGER DEFAULT 3,
|
|
8
|
+
session_id TEXT,
|
|
9
|
+
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
|
10
|
+
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP
|
|
11
|
+
);
|
|
12
|
+
`;
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
// FTS5 全文搜索虚拟表,外部内容模式(external content),不重复存储数据。
|
|
2
|
+
// 创建后索引为空,需要通过 REBUILD 从 memory 主表填充,并依靠 trigger 保持同步。
|
|
3
|
+
export const MEMORY_FTS_TABLE_SQL = `
|
|
4
|
+
CREATE VIRTUAL TABLE IF NOT EXISTS memory_fts USING fts5(
|
|
5
|
+
content,
|
|
6
|
+
keywords,
|
|
7
|
+
content='memory',
|
|
8
|
+
content_rowid='id'
|
|
9
|
+
);
|
|
10
|
+
`;
|
|
11
|
+
// 当 memory 表发生增、删、改时,自动同步到 memory_fts 索引。
|
|
12
|
+
export const MEMORY_FTS_TRIGGERS_SQL = `
|
|
13
|
+
CREATE TRIGGER IF NOT EXISTS memory_fts_insert AFTER INSERT ON memory BEGIN
|
|
14
|
+
INSERT INTO memory_fts(rowid, content, keywords) VALUES (new.id, new.content, new.keywords);
|
|
15
|
+
END;
|
|
16
|
+
|
|
17
|
+
CREATE TRIGGER IF NOT EXISTS memory_fts_delete AFTER DELETE ON memory BEGIN
|
|
18
|
+
INSERT INTO memory_fts(memory_fts, rowid, content, keywords) VALUES('delete', old.id, old.content, old.keywords);
|
|
19
|
+
END;
|
|
20
|
+
|
|
21
|
+
CREATE TRIGGER IF NOT EXISTS memory_fts_update AFTER UPDATE ON memory BEGIN
|
|
22
|
+
INSERT INTO memory_fts(memory_fts, rowid, content, keywords) VALUES('delete', old.id, old.content, old.keywords);
|
|
23
|
+
INSERT INTO memory_fts(rowid, content, keywords) VALUES (new.id, new.content, new.keywords);
|
|
24
|
+
END;
|
|
25
|
+
`;
|
|
26
|
+
// 从 memory 主表重建全文索引。首次创建 memory_fts 后必须执行一次,否则索引为空。
|
|
27
|
+
export const MEMORY_FTS_REBUILD_SQL = `
|
|
28
|
+
INSERT INTO memory_fts(memory_fts) VALUES('rebuild');
|
|
29
|
+
`;
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import * as fs from 'node:fs';
|
|
3
|
+
import { fileURLToPath } from 'node:url';
|
|
4
|
+
import boxen from 'boxen';
|
|
5
|
+
import chalk from 'chalk';
|
|
6
|
+
import figlet from 'figlet';
|
|
7
|
+
import { ensureModelConfig } from './agent/config/index.js';
|
|
8
|
+
import { initializeMcpClients, shutdownMcpClients } from './agent/mcp/index.js';
|
|
9
|
+
import { createCommand, startChat } from './cli/index.js';
|
|
10
|
+
import { isFirstRun, runInstall } from './install.js';
|
|
11
|
+
const packageJsonPath = fileURLToPath(new URL('../package.json', import.meta.url));
|
|
12
|
+
const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8'));
|
|
13
|
+
function renderWelcome() {
|
|
14
|
+
const title = figlet.textSync(packageJson.name, { horizontalLayout: 'fitted' });
|
|
15
|
+
const author = typeof packageJson.author === 'string' ? packageJson.author : packageJson.author?.name;
|
|
16
|
+
const maxLabelWidth = 12;
|
|
17
|
+
const label = (text) => chalk.bold(text.padEnd(maxLabelWidth));
|
|
18
|
+
const header = [
|
|
19
|
+
`${label('Version:')}${packageJson.version}`,
|
|
20
|
+
`${label('Author:')}${author || '暂无作者'}`,
|
|
21
|
+
`${label('Docs:')}${packageJson.docs || '暂无文档'}`,
|
|
22
|
+
].join('\n');
|
|
23
|
+
const description = packageJson.description
|
|
24
|
+
? ` ${chalk.hex('#F59E0B').bold(packageJson.description)}`
|
|
25
|
+
: '';
|
|
26
|
+
const cmdWidth = 20;
|
|
27
|
+
const cmd = (text, color) => color(text.padEnd(cmdWidth));
|
|
28
|
+
const usage = [
|
|
29
|
+
chalk.bold('使用说明'),
|
|
30
|
+
` ${cmd('ESC', chalk.yellow)}取消 AI 请求`,
|
|
31
|
+
` ${cmd('/new', chalk.magenta)}开启新会话`,
|
|
32
|
+
` ${cmd('/compact', chalk.magenta)}手动压缩当前会话上下文`,
|
|
33
|
+
` ${cmd('/session', chalk.magenta)}查看最近会话`,
|
|
34
|
+
` ${cmd('/rewind <thread_id>', chalk.magenta)}恢复指定会话`,
|
|
35
|
+
` ${cmd('exit', chalk.green)}退出`,
|
|
36
|
+
].join('\n');
|
|
37
|
+
const body = [header, description, '', usage].filter(Boolean).join('\n');
|
|
38
|
+
console.log();
|
|
39
|
+
console.log(chalk.hex('#F59E0B').bold(title));
|
|
40
|
+
console.log();
|
|
41
|
+
console.log(boxen(body, {
|
|
42
|
+
padding: { top: 1, bottom: 1, left: 3, right: 3 },
|
|
43
|
+
margin: { top: 0, right: 0, bottom: 1, left: 0 },
|
|
44
|
+
borderColor: 'cyan',
|
|
45
|
+
borderStyle: 'round',
|
|
46
|
+
width: process.stdout.columns || 80,
|
|
47
|
+
}));
|
|
48
|
+
}
|
|
49
|
+
async function main() {
|
|
50
|
+
if (isFirstRun()) {
|
|
51
|
+
await runInstall();
|
|
52
|
+
process.exit(0);
|
|
53
|
+
}
|
|
54
|
+
renderWelcome();
|
|
55
|
+
try {
|
|
56
|
+
await ensureModelConfig();
|
|
57
|
+
}
|
|
58
|
+
catch (err) {
|
|
59
|
+
const message = err.message;
|
|
60
|
+
console.error();
|
|
61
|
+
console.error(boxen(`${chalk.red.bold('缺少 LLM 配置')}\n\n${message}`, {
|
|
62
|
+
padding: { top: 1, bottom: 1, left: 3, right: 3 },
|
|
63
|
+
borderColor: 'red',
|
|
64
|
+
borderStyle: 'round',
|
|
65
|
+
}));
|
|
66
|
+
process.exit(0);
|
|
67
|
+
}
|
|
68
|
+
await initializeMcpClients().catch((err) => {
|
|
69
|
+
console.warn(chalk.yellow(`[MCP] 初始化失败: ${err.message}`));
|
|
70
|
+
});
|
|
71
|
+
const gracefulShutdown = async () => {
|
|
72
|
+
await shutdownMcpClients().catch(() => { });
|
|
73
|
+
process.exit(0);
|
|
74
|
+
};
|
|
75
|
+
process.on('SIGINT', () => gracefulShutdown());
|
|
76
|
+
process.on('SIGTERM', () => gracefulShutdown());
|
|
77
|
+
const program = createCommand();
|
|
78
|
+
// 如果带了命令参数,使用 commander 解析
|
|
79
|
+
// 否则直接进入交互模式(pnpm dev 的情况)
|
|
80
|
+
if (process.argv.length > 2) {
|
|
81
|
+
await program.parseAsync();
|
|
82
|
+
}
|
|
83
|
+
else {
|
|
84
|
+
await startChat();
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
main();
|
package/dist/install.js
ADDED
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
import * as fs from 'node:fs';
|
|
2
|
+
import * as path from 'node:path';
|
|
3
|
+
import chalk from 'chalk';
|
|
4
|
+
import { CONFIG_DIR, CONFIG_FILE } from './agent/config/index.js';
|
|
5
|
+
import { DATA_DIR } from './db/path.js';
|
|
6
|
+
import { initCheckpointer } from './db/checkpointer.js';
|
|
7
|
+
const SKILLS_INSTALL_DIR = path.join(CONFIG_DIR, '.agents', 'skills');
|
|
8
|
+
const DEFAULT_SKILLS = [
|
|
9
|
+
{
|
|
10
|
+
name: 'find-skills',
|
|
11
|
+
owner: 'vercel-labs',
|
|
12
|
+
repo: 'skills',
|
|
13
|
+
path: 'skills/find-skills',
|
|
14
|
+
},
|
|
15
|
+
{
|
|
16
|
+
name: 'skill-creator',
|
|
17
|
+
owner: 'anthropics',
|
|
18
|
+
repo: 'skills',
|
|
19
|
+
path: 'skills/skill-creator',
|
|
20
|
+
},
|
|
21
|
+
];
|
|
22
|
+
const CONFIG_TEMPLATE = {
|
|
23
|
+
model: {
|
|
24
|
+
model: 'kimi-k2.6',
|
|
25
|
+
apiKey: 'your-api-key',
|
|
26
|
+
baseURL: 'https://api.moonshot.cn/v1',
|
|
27
|
+
},
|
|
28
|
+
};
|
|
29
|
+
function printStep(step, total, message) {
|
|
30
|
+
console.log(chalk.cyan(`[${step}/${total}] ${message}`));
|
|
31
|
+
}
|
|
32
|
+
function printSuccess(message) {
|
|
33
|
+
console.log(chalk.green(` ✓ ${message}`));
|
|
34
|
+
}
|
|
35
|
+
function printError(message) {
|
|
36
|
+
console.log(chalk.red(` ✗ ${message}`));
|
|
37
|
+
}
|
|
38
|
+
function printInfo(message) {
|
|
39
|
+
console.log(chalk.gray(` → ${message}`));
|
|
40
|
+
}
|
|
41
|
+
async function fetchGitHubDirectory(owner, repo, dirPath, signal) {
|
|
42
|
+
const url = `https://api.github.com/repos/${owner}/${repo}/contents/${dirPath}`;
|
|
43
|
+
const response = await fetch(url, {
|
|
44
|
+
headers: { 'User-Agent': 'argos-cli' },
|
|
45
|
+
signal,
|
|
46
|
+
});
|
|
47
|
+
if (!response.ok) {
|
|
48
|
+
throw new Error(`Failed to fetch ${url}: ${response.status} ${response.statusText}`);
|
|
49
|
+
}
|
|
50
|
+
return (await response.json());
|
|
51
|
+
}
|
|
52
|
+
async function downloadFile(url, destPath, signal) {
|
|
53
|
+
const response = await fetch(url, { signal });
|
|
54
|
+
if (!response.ok) {
|
|
55
|
+
throw new Error(`Failed to download ${url}: ${response.status} ${response.statusText}`);
|
|
56
|
+
}
|
|
57
|
+
const content = await response.text();
|
|
58
|
+
fs.mkdirSync(path.dirname(destPath), { recursive: true });
|
|
59
|
+
fs.writeFileSync(destPath, content, 'utf8');
|
|
60
|
+
}
|
|
61
|
+
async function installSkill(owner, repo, repoPath, destDir, signal) {
|
|
62
|
+
const items = await fetchGitHubDirectory(owner, repo, repoPath, signal);
|
|
63
|
+
for (const item of items) {
|
|
64
|
+
if (signal.aborted)
|
|
65
|
+
return;
|
|
66
|
+
const destPath = path.join(destDir, item.name);
|
|
67
|
+
if (item.type === 'file' && item.download_url) {
|
|
68
|
+
await downloadFile(item.download_url, destPath, signal);
|
|
69
|
+
}
|
|
70
|
+
else if (item.type === 'dir') {
|
|
71
|
+
await installSkill(owner, repo, item.path, destPath, signal);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
export function isFirstRun() {
|
|
76
|
+
return !fs.existsSync(CONFIG_FILE);
|
|
77
|
+
}
|
|
78
|
+
export function createConfigDirs() {
|
|
79
|
+
fs.mkdirSync(CONFIG_DIR, { recursive: true });
|
|
80
|
+
fs.mkdirSync(DATA_DIR, { recursive: true });
|
|
81
|
+
fs.mkdirSync(SKILLS_INSTALL_DIR, { recursive: true });
|
|
82
|
+
}
|
|
83
|
+
export function initDatabase() {
|
|
84
|
+
initCheckpointer();
|
|
85
|
+
}
|
|
86
|
+
export async function installDefaultSkills() {
|
|
87
|
+
const controller = new AbortController();
|
|
88
|
+
const timeout = setTimeout(() => controller.abort(), 20_000);
|
|
89
|
+
try {
|
|
90
|
+
for (const skill of DEFAULT_SKILLS) {
|
|
91
|
+
if (controller.signal.aborted) {
|
|
92
|
+
printError('skill 安装超时(20s),跳过剩余步骤');
|
|
93
|
+
return;
|
|
94
|
+
}
|
|
95
|
+
const destDir = path.join(SKILLS_INSTALL_DIR, skill.name);
|
|
96
|
+
printInfo(`正在下载 ${skill.name}...`);
|
|
97
|
+
try {
|
|
98
|
+
await installSkill(skill.owner, skill.repo, skill.path, destDir, controller.signal);
|
|
99
|
+
printSuccess(`${skill.name} 安装完成`);
|
|
100
|
+
}
|
|
101
|
+
catch (err) {
|
|
102
|
+
if (err.name === 'AbortError') {
|
|
103
|
+
printError('skill 安装超时(20s),跳过此步骤');
|
|
104
|
+
return;
|
|
105
|
+
}
|
|
106
|
+
printError(`${skill.name} 安装失败: ${err.message}`);
|
|
107
|
+
printInfo('跳过该 skill,后续可手动安装');
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
finally {
|
|
112
|
+
clearTimeout(timeout);
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
export function createConfigFile() {
|
|
116
|
+
if (!fs.existsSync(CONFIG_FILE)) {
|
|
117
|
+
fs.writeFileSync(CONFIG_FILE, JSON.stringify(CONFIG_TEMPLATE, null, 2), 'utf8');
|
|
118
|
+
printSuccess(`配置文件已创建: ${CONFIG_FILE}`);
|
|
119
|
+
}
|
|
120
|
+
else {
|
|
121
|
+
printInfo('配置文件已存在,跳过创建');
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
export async function runInstall() {
|
|
125
|
+
const totalSteps = 4;
|
|
126
|
+
console.log();
|
|
127
|
+
console.log(chalk.bold.hex('#F59E0B')('🚀 欢迎使用 900!首次启动,正在执行初始化...'));
|
|
128
|
+
console.log();
|
|
129
|
+
printStep(1, totalSteps, '创建配置目录...');
|
|
130
|
+
createConfigDirs();
|
|
131
|
+
printSuccess('配置目录已创建');
|
|
132
|
+
printStep(2, totalSteps, '初始化数据库...');
|
|
133
|
+
try {
|
|
134
|
+
initDatabase();
|
|
135
|
+
printSuccess('数据库已初始化');
|
|
136
|
+
}
|
|
137
|
+
catch (err) {
|
|
138
|
+
printError(`数据库初始化失败: ${err.message}`);
|
|
139
|
+
throw err;
|
|
140
|
+
}
|
|
141
|
+
printStep(3, totalSteps, '安装默认 skills...');
|
|
142
|
+
await installDefaultSkills();
|
|
143
|
+
printStep(4, totalSteps, '创建配置文件...');
|
|
144
|
+
createConfigFile();
|
|
145
|
+
console.log();
|
|
146
|
+
console.log(chalk.bold.green('✨ 初始化完成!'));
|
|
147
|
+
console.log();
|
|
148
|
+
console.log(chalk.yellow.bold('⚠️ 请修改配置文件后再使用:') + chalk.cyan(CONFIG_FILE));
|
|
149
|
+
console.log(chalk.gray(' 请将 apiKey 替换为您的真实 API Key。'));
|
|
150
|
+
console.log();
|
|
151
|
+
console.log(chalk.bold('启动命令:'));
|
|
152
|
+
console.log(chalk.cyan(' 900'));
|
|
153
|
+
console.log();
|
|
154
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "nine-hundred",
|
|
3
|
+
"version": "0.0.1",
|
|
4
|
+
"description": "你好,我是 900。往后你只管往前走,杂事我来盯。",
|
|
5
|
+
"keywords": [],
|
|
6
|
+
"license": "ISC",
|
|
7
|
+
"author": "lyvvq9296",
|
|
8
|
+
"bin": {
|
|
9
|
+
"900": "./dist/index.js"
|
|
10
|
+
},
|
|
11
|
+
"type": "module",
|
|
12
|
+
"scripts": {
|
|
13
|
+
"test": "vitest run",
|
|
14
|
+
"test:watch": "vitest",
|
|
15
|
+
"typecheck": "tsc --noEmit",
|
|
16
|
+
"build": "tsc -p tsconfig.build.json && tsc-alias -p tsconfig.build.json && chmod +x dist/index.js",
|
|
17
|
+
"lint": "oxlint",
|
|
18
|
+
"lint:fix": "oxlint --fix",
|
|
19
|
+
"format": "oxfmt",
|
|
20
|
+
"format:check": "oxfmt --check",
|
|
21
|
+
"dev": "dotenvx run -- tsx src/index.ts",
|
|
22
|
+
"start": "node dist/index.js"
|
|
23
|
+
},
|
|
24
|
+
"dependencies": {
|
|
25
|
+
"@langchain/core": "^1.1.48",
|
|
26
|
+
"@langchain/langgraph": "^1.3.5",
|
|
27
|
+
"@langchain/langgraph-checkpoint-sqlite": "^1.0.3",
|
|
28
|
+
"@langchain/openai": "^1.4.7",
|
|
29
|
+
"@langchain/tavily": "^1.2.0",
|
|
30
|
+
"@modelcontextprotocol/sdk": "1.29.0",
|
|
31
|
+
"better-sqlite3": "^12.11.1",
|
|
32
|
+
"boxen": "^8.0.1",
|
|
33
|
+
"chalk": "^5.6.2",
|
|
34
|
+
"cli-table3": "^0.6.5",
|
|
35
|
+
"commander": "^15.0.0",
|
|
36
|
+
"figlet": "^1.11.0",
|
|
37
|
+
"langchain": "^1.4.4",
|
|
38
|
+
"zod": "^4.4.3"
|
|
39
|
+
},
|
|
40
|
+
"devDependencies": {
|
|
41
|
+
"@dotenvx/dotenvx": "^1.71.3",
|
|
42
|
+
"@types/node": "^25.9.1",
|
|
43
|
+
"oxfmt": "^0.53.0",
|
|
44
|
+
"oxlint": "^1.68.0",
|
|
45
|
+
"tsc-alias": "^1.8.17",
|
|
46
|
+
"tsx": "^4.22.4",
|
|
47
|
+
"typescript": "7.0.1-rc",
|
|
48
|
+
"vitest": "^4.1.8"
|
|
49
|
+
},
|
|
50
|
+
"packageManager": "pnpm@11.9.0"
|
|
51
|
+
}
|