@mazjq/zhiro 0.0.0-stage → 0.2.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/LICENSE +21 -0
- package/README.md +228 -2
- package/README.zh-CN.md +188 -0
- package/agent-skills/zhiro/SKILL.md +89 -0
- package/bin/zhiro.cjs +21 -0
- package/dist/acp-bridge.js +87 -0
- package/dist/chunk-2SSYR7VW.js +558 -0
- package/dist/chunk-2XJ45GUM.js +3795 -0
- package/dist/chunk-4EPNDXRS.js +542 -0
- package/dist/chunk-4JJEOOW2.js +107 -0
- package/dist/chunk-4UWMDKMH.js +2605 -0
- package/dist/chunk-7IV2NG2D.js +328 -0
- package/dist/chunk-A722HITH.js +680 -0
- package/dist/chunk-GRZ4VMSO.js +180 -0
- package/dist/chunk-H3EFVYGD.js +6 -0
- package/dist/chunk-OOHBM3BT.js +6 -0
- package/dist/chunk-VOUILWMI.js +848 -0
- package/dist/chunk-ZKD2BKN3.js +1158 -0
- package/dist/chunk-ZUUYRVX6.js +44 -0
- package/dist/cli-LUWVZ5NG.js +131 -0
- package/dist/login-W5QYFWTY.js +75 -0
- package/dist/main-FTWFKWZH.js +8029 -0
- package/dist/research-data.js +46 -0
- package/dist/stdio-FZZLZI4P.js +32 -0
- package/dist/vault-JUTREQJK.js +117 -0
- package/dist/zhiro.js +62 -0
- package/package.json +57 -4
- package/ui/assets/core-CwxXejkd.js +1 -0
- package/ui/assets/index-B7GrU8uc.js +39 -0
- package/ui/assets/index-Dt8b-A97.css +2 -0
- package/ui/index.html +15 -0
- package/ui/tauri.svg +6 -0
- package/ui/vite.svg +1 -0
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import {
|
|
2
|
+
DATA_TOOLS,
|
|
3
|
+
callData,
|
|
4
|
+
dataFile,
|
|
5
|
+
tools
|
|
6
|
+
} from "./chunk-2XJ45GUM.js";
|
|
7
|
+
import "./chunk-VOUILWMI.js";
|
|
8
|
+
import "./chunk-H3EFVYGD.js";
|
|
9
|
+
import "./chunk-7IV2NG2D.js";
|
|
10
|
+
import "./chunk-ZKD2BKN3.js";
|
|
11
|
+
import "./chunk-4UWMDKMH.js";
|
|
12
|
+
import "./chunk-4EPNDXRS.js";
|
|
13
|
+
import "./chunk-4JJEOOW2.js";
|
|
14
|
+
import {
|
|
15
|
+
__name
|
|
16
|
+
} from "./chunk-2SSYR7VW.js";
|
|
17
|
+
|
|
18
|
+
// apps/daemon/src/mcp/research-data.ts
|
|
19
|
+
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
|
|
20
|
+
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
21
|
+
import { CallToolRequestSchema, ListToolsRequestSchema } from "@modelcontextprotocol/sdk/types.js";
|
|
22
|
+
var file = process.env.JOBOS_RUN_DIR ? dataFile(process.env.JOBOS_RUN_DIR) : void 0;
|
|
23
|
+
var names = Object.keys(DATA_TOOLS);
|
|
24
|
+
var wireName = /* @__PURE__ */ __name((n) => n.replace(".", "_"), "wireName");
|
|
25
|
+
var inWireNames = /* @__PURE__ */ __name((text) => names.reduce((t, n) => t.split(n).join(wireName(n)), text), "inWireNames");
|
|
26
|
+
var server = new Server({ name: "jobos-data", version: "0.0.1" }, { capabilities: { tools: {} } });
|
|
27
|
+
server.setRequestHandler(ListToolsRequestSchema, async () => ({
|
|
28
|
+
tools: names.map((n) => {
|
|
29
|
+
const input = tools[n].input;
|
|
30
|
+
const { runId: _run, ...properties } = input.properties;
|
|
31
|
+
return { name: wireName(n), description: inWireNames(tools[n].description), inputSchema: { type: "object", properties, required: (input.required ?? []).filter((r) => r !== "runId") } };
|
|
32
|
+
})
|
|
33
|
+
}));
|
|
34
|
+
server.setRequestHandler(CallToolRequestSchema, async (req) => {
|
|
35
|
+
const tool = names.find((n) => wireName(n) === req.params.name);
|
|
36
|
+
if (!tool) return { isError: true, content: [{ type: "text", text: `unknown tool ${req.params.name}` }] };
|
|
37
|
+
try {
|
|
38
|
+
return { content: [{ type: "text", text: JSON.stringify(await callData(tool, req.params.arguments ?? {}, file)) }] };
|
|
39
|
+
} catch (e) {
|
|
40
|
+
return { isError: true, content: [{ type: "text", text: String(e?.message ?? e) }] };
|
|
41
|
+
}
|
|
42
|
+
});
|
|
43
|
+
await server.connect(new StdioServerTransport());
|
|
44
|
+
export {
|
|
45
|
+
wireName
|
|
46
|
+
};
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import "./chunk-OOHBM3BT.js";
|
|
2
|
+
import {
|
|
3
|
+
defaultVaultDir
|
|
4
|
+
} from "./chunk-4JJEOOW2.js";
|
|
5
|
+
import "./chunk-2SSYR7VW.js";
|
|
6
|
+
|
|
7
|
+
// apps/daemon/src/mcp/stdio.ts
|
|
8
|
+
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
9
|
+
import { StreamableHTTPClientTransport } from "@modelcontextprotocol/sdk/client/streamableHttp.js";
|
|
10
|
+
import { readFileSync } from "node:fs";
|
|
11
|
+
import { join } from "node:path";
|
|
12
|
+
var vault = defaultVaultDir();
|
|
13
|
+
var base = process.env.JOBOS_URL ?? "http://127.0.0.1:8787";
|
|
14
|
+
var token = process.env.JOBOS_AGENT_TOKEN ?? readFileSync(join(vault, "config", ".agent-token"), "utf8").trim();
|
|
15
|
+
var actorVia = process.env.JOBOS_ACTOR ?? "mcp";
|
|
16
|
+
var down = new StdioServerTransport();
|
|
17
|
+
var resultMode = process.env.JOBOS_RESULT_MODE === "text" ? { "x-zhiro-result-mode": "text" } : {};
|
|
18
|
+
var up = new StreamableHTTPClientTransport(new URL("/mcp", base), { requestInit: { headers: { authorization: `Bearer ${token}`, "x-jobos-actor": actorVia, ...resultMode } } });
|
|
19
|
+
down.onmessage = (m) => {
|
|
20
|
+
up.send(m).catch((e) => {
|
|
21
|
+
if (!("id" in m) || !("method" in m)) return;
|
|
22
|
+
const why = /fetch failed|ECONNREFUSED/i.test(String(e?.cause?.code ?? e?.message)) ? `Zhiro 没在运行(${base} 连不上),请先启动 Zhiro` : String(e?.message ?? e);
|
|
23
|
+
void down.send({ jsonrpc: "2.0", id: m.id, error: { code: -32e3, message: why } });
|
|
24
|
+
});
|
|
25
|
+
};
|
|
26
|
+
up.onmessage = (m) => void down.send(m);
|
|
27
|
+
down.onclose = () => {
|
|
28
|
+
void up.close();
|
|
29
|
+
process.exit(0);
|
|
30
|
+
};
|
|
31
|
+
await up.start();
|
|
32
|
+
await down.start();
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
import {
|
|
2
|
+
defaultExportPath,
|
|
3
|
+
exportVault,
|
|
4
|
+
importVault,
|
|
5
|
+
preUpgradeBackups,
|
|
6
|
+
rollbackVault,
|
|
7
|
+
runBackup,
|
|
8
|
+
upgradeVault,
|
|
9
|
+
verifyVault
|
|
10
|
+
} from "./chunk-A722HITH.js";
|
|
11
|
+
import "./chunk-H3EFVYGD.js";
|
|
12
|
+
import {
|
|
13
|
+
openDb
|
|
14
|
+
} from "./chunk-4EPNDXRS.js";
|
|
15
|
+
import {
|
|
16
|
+
dbPath,
|
|
17
|
+
defaultVaultDir
|
|
18
|
+
} from "./chunk-4JJEOOW2.js";
|
|
19
|
+
import {
|
|
20
|
+
VaultBusy,
|
|
21
|
+
__name,
|
|
22
|
+
cancelMove,
|
|
23
|
+
lockVault,
|
|
24
|
+
pointerFile,
|
|
25
|
+
requestMove,
|
|
26
|
+
writePointer
|
|
27
|
+
} from "./chunk-2SSYR7VW.js";
|
|
28
|
+
|
|
29
|
+
// apps/daemon/src/cli/vault.ts
|
|
30
|
+
import { DatabaseSync } from "node:sqlite";
|
|
31
|
+
import { existsSync, readdirSync } from "node:fs";
|
|
32
|
+
import { resolve } from "node:path";
|
|
33
|
+
var [cmd, arg] = process.argv.slice(2);
|
|
34
|
+
var vault = defaultVaultDir();
|
|
35
|
+
async function locked(who) {
|
|
36
|
+
try {
|
|
37
|
+
return await lockVault(vault, who);
|
|
38
|
+
} catch (e) {
|
|
39
|
+
console.error(e instanceof VaultBusy ? `${e.message}
|
|
40
|
+
先停掉 daemon 再做。` : String(e?.message ?? e));
|
|
41
|
+
process.exit(1);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
__name(locked, "locked");
|
|
45
|
+
if (cmd === "export") {
|
|
46
|
+
const db = openDb(dbPath(vault));
|
|
47
|
+
const r = exportVault(db, vault, arg ?? defaultExportPath());
|
|
48
|
+
db.close();
|
|
49
|
+
console.log(`exported ${r.path} (${(r.bytes / 1e6).toFixed(1)} MB): ${Object.entries(r.manifest.counts).map(([k, v]) => `${k} ${v}`).join(", ")}; ${r.manifest.files} files`);
|
|
50
|
+
} else if (cmd === "verify") {
|
|
51
|
+
const r = verifyVault(vault, { quick: arg === "--quick" });
|
|
52
|
+
console.log(`数据目录 ${vault}:数据库 v${r.schema},程序 v${r.program}`);
|
|
53
|
+
console.log(Object.entries(r.counts).filter(([, n]) => n).map(([k, n]) => `${k} ${n}`).join(", "));
|
|
54
|
+
console.log(r.ok ? "检查通过" : `有问题:
|
|
55
|
+
- ${r.problems.join("\n- ")}`);
|
|
56
|
+
process.exitCode = r.ok ? 0 : 1;
|
|
57
|
+
} else if (cmd === "upgrade" || cmd === "rollback") {
|
|
58
|
+
const lock = await locked(`vault ${cmd}`);
|
|
59
|
+
try {
|
|
60
|
+
if (cmd === "upgrade") {
|
|
61
|
+
const r = upgradeVault(vault, lock, { log: console.log });
|
|
62
|
+
if (!r) console.log("不用升级");
|
|
63
|
+
} else {
|
|
64
|
+
if (!arg) console.log(`升级前的备份:${preUpgradeBackups(vault).join("、") || "(没有)"};用最新的那份`);
|
|
65
|
+
const r = rollbackVault(vault, lock, arg);
|
|
66
|
+
console.log(`已换回 ${r.restored}(数据库 v${r.manifest.fromSchema})。换下来的库留在 ${r.kept}`);
|
|
67
|
+
console.log(r.manifest.fromApp ? `这份数据配 ${r.manifest.fromApp}:npm i -g @mazjq/zhiro@${r.manifest.fromApp}` : "这份数据配升级前用的那个版本(它没有记下版本号);装回那个版本再启动");
|
|
68
|
+
}
|
|
69
|
+
} catch (e) {
|
|
70
|
+
console.error(String(e?.message ?? e));
|
|
71
|
+
process.exitCode = 1;
|
|
72
|
+
} finally {
|
|
73
|
+
await lock.release();
|
|
74
|
+
}
|
|
75
|
+
} else if (cmd === "import" && arg) {
|
|
76
|
+
const lock = await locked("vault import");
|
|
77
|
+
try {
|
|
78
|
+
const r = importVault(vault, arg, lock);
|
|
79
|
+
console.log(`imported into ${vault}; the previous database is at ${r.backup}`);
|
|
80
|
+
console.log(`before: ${Object.entries(r.before).map(([k, v]) => `${k} ${v}`).join(", ") || "(none)"}`);
|
|
81
|
+
console.log(`after: ${Object.entries(r.after).map(([k, v]) => `${k} ${v}`).join(", ")}; ${r.files} files; schema v${r.schemaVersion}`);
|
|
82
|
+
} finally {
|
|
83
|
+
lock.release();
|
|
84
|
+
}
|
|
85
|
+
} else if (cmd === "backup") {
|
|
86
|
+
const db = new DatabaseSync(dbPath(vault), { readOnly: true });
|
|
87
|
+
try {
|
|
88
|
+
const r = runBackup(db, vault);
|
|
89
|
+
console.log(`backup ${r.path} (${(r.bytes / 1e6).toFixed(1)} MB), checked${r.config ? `; config without secrets ${r.config}` : ""}`);
|
|
90
|
+
} catch (e) {
|
|
91
|
+
console.error(String(e?.message ?? e));
|
|
92
|
+
process.exitCode = 1;
|
|
93
|
+
} finally {
|
|
94
|
+
db.close();
|
|
95
|
+
}
|
|
96
|
+
} else if (cmd === "use" && arg) {
|
|
97
|
+
const dir = resolve(arg);
|
|
98
|
+
if (existsSync(dir) && readdirSync(dir).length && !existsSync(dbPath(dir))) {
|
|
99
|
+
console.error(`${dir} 里已经有别的东西,又不是 Zhiro 的数据文件夹:换一个空文件夹`);
|
|
100
|
+
process.exit(1);
|
|
101
|
+
}
|
|
102
|
+
writePointer(dir);
|
|
103
|
+
console.log(`以后用 ${dir}(记在 ${pointerFile()})`);
|
|
104
|
+
} else if (cmd === "move" && arg) {
|
|
105
|
+
try {
|
|
106
|
+
if (arg === "--cancel") {
|
|
107
|
+
cancelMove(vault);
|
|
108
|
+
console.log("cancelled");
|
|
109
|
+
} else console.log(`noted: at the next start of the daemon the data moves to ${requestMove(vault, arg).to}`);
|
|
110
|
+
} catch (e) {
|
|
111
|
+
console.error(String(e?.message ?? e));
|
|
112
|
+
process.exitCode = 1;
|
|
113
|
+
}
|
|
114
|
+
} else {
|
|
115
|
+
console.error("usage: vault verify [--quick] | vault use <folder> | vault backup | vault upgrade | vault rollback [backup] | vault move <folder> | vault export [file.zip] | vault import <file.zip>");
|
|
116
|
+
process.exit(2);
|
|
117
|
+
}
|
package/dist/zhiro.js
ADDED
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import "./chunk-OOHBM3BT.js";
|
|
2
|
+
import {
|
|
3
|
+
VERSION
|
|
4
|
+
} from "./chunk-H3EFVYGD.js";
|
|
5
|
+
import {
|
|
6
|
+
__name,
|
|
7
|
+
dataDir
|
|
8
|
+
} from "./chunk-2SSYR7VW.js";
|
|
9
|
+
|
|
10
|
+
// apps/daemon/src/cli/zhiro.ts
|
|
11
|
+
var HELP = `Zhiro · 职路 ${VERSION} — AI 职业调研与求职(本地优先)
|
|
12
|
+
|
|
13
|
+
用法:
|
|
14
|
+
zhiro [--data <文件夹>] [--no-open] 启动(打开界面;数据默认放在系统惯例位置,第一次启动会问)
|
|
15
|
+
zhiro mcp 给你自己的 agent 用的 MCP(stdio)
|
|
16
|
+
zhiro vault verify [--quick] 检查数据是否完整(随时可跑)
|
|
17
|
+
zhiro vault backup 备份一次
|
|
18
|
+
zhiro vault upgrade | rollback 升级数据库 / 回到升级前(先停掉 zhiro)
|
|
19
|
+
zhiro vault use <文件夹> 以后都用这个数据文件夹(新的,或已有的数据)
|
|
20
|
+
zhiro vault move <文件夹> 下次启动时把数据搬过去
|
|
21
|
+
zhiro vault export [x.zip] | import <x.zip>
|
|
22
|
+
zhiro data probe|add|list|sync|watch 岗位订阅(表格、招聘站)
|
|
23
|
+
zhiro auth <供应商> 内置助手的模型登录(可选)
|
|
24
|
+
zhiro --version
|
|
25
|
+
|
|
26
|
+
文档:https://github.com/mazjq/zhiro`;
|
|
27
|
+
var args = process.argv.slice(2);
|
|
28
|
+
var first = args.find((a, i) => !a.startsWith("-") && args[i - 1] !== "--data");
|
|
29
|
+
if (args.includes("--version") || args.includes("-v")) {
|
|
30
|
+
console.log(VERSION);
|
|
31
|
+
process.exit(0);
|
|
32
|
+
}
|
|
33
|
+
if (args.includes("--help") || args.includes("-h") || first === "help") {
|
|
34
|
+
console.log(HELP);
|
|
35
|
+
process.exit(0);
|
|
36
|
+
}
|
|
37
|
+
var sub = first ?? "start";
|
|
38
|
+
var MODULES = {
|
|
39
|
+
start: /* @__PURE__ */ __name(() => import("./main-FTWFKWZH.js"), "start"),
|
|
40
|
+
mcp: /* @__PURE__ */ __name(() => import("./stdio-FZZLZI4P.js"), "mcp"),
|
|
41
|
+
vault: /* @__PURE__ */ __name(() => import("./vault-JUTREQJK.js"), "vault"),
|
|
42
|
+
data: /* @__PURE__ */ __name(() => import("./cli-LUWVZ5NG.js"), "data"),
|
|
43
|
+
auth: /* @__PURE__ */ __name(() => import("./login-W5QYFWTY.js"), "auth")
|
|
44
|
+
};
|
|
45
|
+
if (!MODULES[sub]) {
|
|
46
|
+
console.error(`不认识的命令:${sub}
|
|
47
|
+
|
|
48
|
+
${HELP}`);
|
|
49
|
+
process.exit(2);
|
|
50
|
+
}
|
|
51
|
+
try {
|
|
52
|
+
dataDir();
|
|
53
|
+
} catch (e) {
|
|
54
|
+
console.error(`[zhiro] ${e?.message ?? e}`);
|
|
55
|
+
process.exit(1);
|
|
56
|
+
}
|
|
57
|
+
var rest = args.filter((a, i) => a !== sub || i !== args.indexOf(sub)).filter((a, i, all) => a !== "--data" && all[i - 1] !== "--data" && !a.startsWith("--data="));
|
|
58
|
+
if (sub === "start") {
|
|
59
|
+
if (process.stdout.isTTY && !rest.includes("--no-open")) process.env.ZHIRO_OPEN = "1";
|
|
60
|
+
}
|
|
61
|
+
process.argv = [process.argv[0], process.argv[1], ...rest.filter((a) => a !== "--no-open")];
|
|
62
|
+
await MODULES[sub]();
|
package/package.json
CHANGED
|
@@ -1,6 +1,59 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mazjq/zhiro",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"
|
|
5
|
-
"
|
|
6
|
-
|
|
3
|
+
"version": "0.2.1",
|
|
4
|
+
"description": "Zhiro · 职路 — find the best career path open to you: opportunity gaps, company research (financials, R&D, incentives), every job and deadline, with your own AI agent over MCP",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"author": "mazjq",
|
|
7
|
+
"homepage": "https://github.com/mazjq/zhiro",
|
|
8
|
+
"repository": {
|
|
9
|
+
"type": "git",
|
|
10
|
+
"url": "git+https://github.com/mazjq/zhiro.git"
|
|
11
|
+
},
|
|
12
|
+
"bugs": "https://github.com/mazjq/zhiro/issues",
|
|
13
|
+
"keywords": [
|
|
14
|
+
"job-search",
|
|
15
|
+
"career",
|
|
16
|
+
"campus-recruiting",
|
|
17
|
+
"mcp",
|
|
18
|
+
"agent",
|
|
19
|
+
"local-first",
|
|
20
|
+
"校招",
|
|
21
|
+
"求职"
|
|
22
|
+
],
|
|
23
|
+
"type": "module",
|
|
24
|
+
"bin": {
|
|
25
|
+
"zhiro": "bin/zhiro.cjs"
|
|
26
|
+
},
|
|
27
|
+
"files": [
|
|
28
|
+
"bin",
|
|
29
|
+
"dist",
|
|
30
|
+
"ui",
|
|
31
|
+
"agent-skills",
|
|
32
|
+
"LICENSE",
|
|
33
|
+
"README.md",
|
|
34
|
+
"README.zh-CN.md"
|
|
35
|
+
],
|
|
36
|
+
"engines": {
|
|
37
|
+
"node": ">=22.13"
|
|
38
|
+
},
|
|
39
|
+
"dependencies": {
|
|
40
|
+
"@agentclientprotocol/sdk": "1.8.0",
|
|
41
|
+
"@earendil-works/pi-agent-core": "^1.0.0",
|
|
42
|
+
"@earendil-works/pi-ai": "^1.0.0",
|
|
43
|
+
"@earendil-works/pi-session-backend-sqlite-node": "^0.99.2",
|
|
44
|
+
"@hono/node-server": "^2.1.1",
|
|
45
|
+
"@larksuiteoapi/node-sdk": "^1.73.3",
|
|
46
|
+
"@modelcontextprotocol/sdk": "^1.30.0",
|
|
47
|
+
"@sinclair/typebox": "^0.34.52",
|
|
48
|
+
"croner": "^10.0.1",
|
|
49
|
+
"hono": "^4.13.7",
|
|
50
|
+
"imapflow": "^2.0.5",
|
|
51
|
+
"jpeg-js": "^0.4.4",
|
|
52
|
+
"jsqr": "^1.4.0",
|
|
53
|
+
"mailparser": "^3.9.28",
|
|
54
|
+
"playwright-core": "^1.63.0",
|
|
55
|
+
"pngjs": "^7.0.0",
|
|
56
|
+
"ulid": "^3.0.2",
|
|
57
|
+
"yaml": "^2.9.1"
|
|
58
|
+
}
|
|
59
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
async function e(e,t={},n){return window.__TAURI_INTERNALS__.invoke(e,t,n)}export{e as invoke};
|