wezard 1.4.1 → 2.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/CLAUDE.md +12 -7
- package/README.md +227 -112
- package/cli/wezard.sh +6 -3
- package/dist/daemon/approval.js +9 -3
- package/dist/daemon/approval.js.map +1 -1
- package/dist/daemon/cc-bridge.js.map +1 -1
- package/dist/daemon/chat-name.js +8 -14
- package/dist/daemon/chat-name.js.map +1 -1
- package/dist/daemon/detail.js +94 -9
- package/dist/daemon/detail.js.map +1 -1
- package/dist/daemon/graph.js +5 -7
- package/dist/daemon/graph.js.map +1 -1
- package/dist/daemon/inbound.js +135 -158
- package/dist/daemon/inbound.js.map +1 -1
- package/dist/daemon/index.js +452 -156
- package/dist/daemon/index.js.map +1 -1
- package/dist/daemon/jobs.js +2 -2
- package/dist/daemon/mirror-bridge.js +284 -140
- package/dist/daemon/mirror-bridge.js.map +1 -1
- package/dist/daemon/mirror-store.js.map +1 -1
- package/dist/daemon/model-select.js +74 -0
- package/dist/daemon/model-select.js.map +1 -0
- package/dist/daemon/peers.js +10 -16
- package/dist/daemon/peers.js.map +1 -1
- package/dist/daemon/spawn-tmux.js +27 -4
- package/dist/daemon/spawn-tmux.js.map +1 -1
- package/dist/daemon/task-gate.js +97 -0
- package/dist/daemon/task-gate.js.map +1 -0
- package/dist/daemon/task-registry.js +132 -0
- package/dist/daemon/task-registry.js.map +1 -0
- package/dist/daemon/tasks.js +126 -54
- package/dist/daemon/tasks.js.map +1 -1
- package/dist/daemon/wizard-memory.js +57 -0
- package/dist/daemon/wizard-memory.js.map +1 -0
- package/dist/daemon/wizard.js +84 -36
- package/dist/daemon/wizard.js.map +1 -1
- package/dist/mcp/server.js +138 -76
- package/dist/mcp/server.js.map +1 -1
- package/dist/shared/chat-http.js +193 -96
- package/dist/shared/chat-http.js.map +1 -1
- package/dist/shared/chat-render.js +31 -24
- package/dist/shared/chat-render.js.map +1 -1
- package/dist/shared/chat-view.js +14 -2
- package/dist/shared/chat-view.js.map +1 -1
- package/dist/shared/config.js +23 -4
- package/dist/shared/config.js.map +1 -1
- package/dist/shared/detail-render.js +14 -7
- package/dist/shared/detail-render.js.map +1 -1
- package/dist/shared/detail-store.js +12 -5
- package/dist/shared/detail-store.js.map +1 -1
- package/dist/shared/role-render.js +52 -0
- package/dist/shared/role-render.js.map +1 -0
- package/dist/shared/role-view.js +210 -0
- package/dist/shared/role-view.js.map +1 -0
- package/dist/shared/schedule-spec.js +92 -116
- package/dist/shared/schedule-spec.js.map +1 -1
- package/dist/shared/session-label.js +103 -72
- package/dist/shared/session-label.js.map +1 -1
- package/dist/shared/std.js +20 -0
- package/dist/shared/std.js.map +1 -1
- package/dist/shared/task-file.js +120 -0
- package/dist/shared/task-file.js.map +1 -0
- package/dist/shared/trigger.js +232 -0
- package/dist/shared/trigger.js.map +1 -0
- package/dist/shared/world.js +193 -0
- package/dist/shared/world.js.map +1 -0
- package/dist/svr/index.js +68 -3
- package/dist/svr/index.js.map +1 -1
- package/package.json +1 -1
- package/web/chat.css +609 -147
- package/web/chat.js +1274 -215
package/dist/daemon/tasks.js
CHANGED
|
@@ -1,87 +1,159 @@
|
|
|
1
|
-
import { randomUUID } from "node:crypto";
|
|
2
1
|
import { patchJsonc } from "../shared/config-writer.js";
|
|
3
2
|
import { baseOfKey, withTagHeader } from "../shared/session-label.js";
|
|
4
|
-
import {
|
|
3
|
+
import { interpolate } from "../shared/std.js";
|
|
4
|
+
import { describeTrigger, isDue, nextFire, triggerOfLegacyWhen } from "../shared/trigger.js";
|
|
5
|
+
import { slugify, uniqueId } from "../shared/task-file.js";
|
|
6
|
+
import { runGate } from "./task-gate.js";
|
|
5
7
|
const stripPrefix = (s) => {
|
|
6
8
|
const i = s.indexOf(":");
|
|
7
9
|
return i >= 0 ? s.slice(i + 1) : s;
|
|
8
10
|
};
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
};
|
|
24
|
-
export const removeScheduleById = (cfg, sourcePath, id) => {
|
|
25
|
-
const hit = cfg.schedules.find((s) => s.id === id);
|
|
26
|
-
if (!hit)
|
|
27
|
-
return undefined;
|
|
28
|
-
cfg.schedules = cfg.schedules.filter((s) => s !== hit);
|
|
29
|
-
persist(cfg, sourcePath);
|
|
30
|
-
return hit;
|
|
31
|
-
};
|
|
32
|
-
/** 给出 `target` 就只列排给那个 wizard 的。 */
|
|
33
|
-
export const listSchedules = (cfg, target) => target ? cfg.schedules.filter((s) => s.target === target) : cfg.schedules;
|
|
11
|
+
// 一条定时的 prompt 本身就在说「建一个 wizard 去干这件事」时, 它要的显然不是
|
|
12
|
+
// 在某个已有会话里续 —— 哪怕排班时点了 tag, 那个 tag 也只是「在谁的聊天/目录下
|
|
13
|
+
// 办」。这条推断放在 daemon 而不是靠调用方记得传 fresh: 排班的模型换一个就忘了,
|
|
14
|
+
// 而这句话的意思一直写在 prompt 里。否定说法 (「不用新建」「无需另起」) 不算。
|
|
15
|
+
const SPAWN = "(?:新建|新起|新开|另起|创建|建立|拉起|开|起|建|spawn|create|new)";
|
|
16
|
+
const COUNT = "\\s*(?:一|两|二|三|四|五|[0-9]+)?\\s*(?:个|名|只)?\\s*";
|
|
17
|
+
const AGENT = "(?:wizard|分身|clone|会话|session)";
|
|
18
|
+
const WISH = new RegExp(SPAWN + COUNT + AGENT, "i");
|
|
19
|
+
// 否定说法先抹掉再判: 「不用新建 wizard」里的「建 wizard」照样能被 WISH 咬住,
|
|
20
|
+
// 单靠 lookbehind 拦不住 —— 它只挡得住整句里最长的那一次匹配。
|
|
21
|
+
const NEGATED = new RegExp("(?:不|别|勿|无|免)(?:用|需|要)?\\s*" + SPAWN + COUNT + AGENT, "gi");
|
|
22
|
+
export const promptWantsFreshWizard = (prompt) => WISH.test(prompt.replace(NEGATED, ""));
|
|
23
|
+
/** 一条任务的 `since`: 上次放枪, 没放过就从建表那一刻算 —— 刚建好不立刻打一枪。 */
|
|
24
|
+
export const sinceOf = (s) => s.lastFired ?? s.createdAt ?? Date.now();
|
|
34
25
|
/** 列表回显: 规格与下次触发都摊成人话, 调用方直接念给用户听。 */
|
|
35
|
-
export const
|
|
36
|
-
id:
|
|
37
|
-
when:
|
|
38
|
-
next: new Date(nextFire(
|
|
26
|
+
export const renderTask = (t, s, now = new Date(), error) => ({
|
|
27
|
+
id: t.id,
|
|
28
|
+
when: describeTrigger(t.trigger),
|
|
29
|
+
next: t.enabled ? new Date(nextFire(t.trigger, sinceOf(s), now)).toLocaleString("zh-CN", { hour12: false }) : "(已暂停)",
|
|
39
30
|
lastFired: s.lastFired ? new Date(s.lastFired).toLocaleString("zh-CN", { hour12: false }) : "",
|
|
40
|
-
note:
|
|
41
|
-
|
|
42
|
-
|
|
31
|
+
note: t.note,
|
|
32
|
+
runIn: t.fresh ? "每次新建一个白板 wizard 执行, 跑完自动回收" : "注入已有会话",
|
|
33
|
+
target: t.target,
|
|
34
|
+
owner: t.owner,
|
|
35
|
+
prompt: t.prompt,
|
|
36
|
+
/** wizard 要改这条定时, 直接 Read/Edit 这个文件。 */
|
|
37
|
+
file: t.file,
|
|
38
|
+
...(t.hasGate ? { gate: `有 (上一轮: ${s.lastGate ?? "未跑过"})` } : {}),
|
|
39
|
+
...(s.lastError ? { lastError: s.lastError } : {}),
|
|
40
|
+
...(error ? { loadError: error } : {}),
|
|
43
41
|
});
|
|
42
|
+
// ── 迁移 ──────────────────────────────────────────────────────────
|
|
43
|
+
/** 1.5 之前定时住在 config.jsonc 的 `schedules` 数组里。就地抬成任务文件, 抬完清表
|
|
44
|
+
* —— 两处都留着会放两次枪。 */
|
|
45
|
+
export const migrateLegacySchedules = (cfg, sourcePath, registry, log) => {
|
|
46
|
+
if (!cfg.schedules.length)
|
|
47
|
+
return 0;
|
|
48
|
+
const taken = registry.takenIds();
|
|
49
|
+
const moved = cfg.schedules.map((s) => {
|
|
50
|
+
const id = uniqueId(slugify(s.note || s.prompt.slice(0, 24), `task-${s.id}`), taken);
|
|
51
|
+
taken.add(id);
|
|
52
|
+
const r = registry.create({
|
|
53
|
+
id,
|
|
54
|
+
trigger: triggerOfLegacyWhen(s.when),
|
|
55
|
+
prompt: s.prompt,
|
|
56
|
+
target: s.target,
|
|
57
|
+
fresh: s.fresh,
|
|
58
|
+
note: s.note,
|
|
59
|
+
createdBy: s.createdBy,
|
|
60
|
+
});
|
|
61
|
+
if ("error" in r) {
|
|
62
|
+
log.warn({ old: s.id, err: r.error }, "schedule migration failed");
|
|
63
|
+
return 0;
|
|
64
|
+
}
|
|
65
|
+
if (s.lastFired)
|
|
66
|
+
registry.patchState(id, { lastFired: s.lastFired, createdAt: s.createdAt });
|
|
67
|
+
else
|
|
68
|
+
registry.patchState(id, { createdAt: s.createdAt || Date.now() });
|
|
69
|
+
return 1;
|
|
70
|
+
}).reduce((a, b) => a + b, 0);
|
|
71
|
+
cfg.schedules = [];
|
|
72
|
+
patchJsonc(sourcePath, [{ path: ["schedules"], value: [] }]);
|
|
73
|
+
log.info({ moved, dir: registry.dir }, "schedules migrated to task files");
|
|
74
|
+
return moved;
|
|
75
|
+
};
|
|
44
76
|
const announce = async (client, target, markdown) => {
|
|
45
77
|
await client.sendMessage(stripPrefix(baseOfKey(target)), {
|
|
46
78
|
msgtype: "markdown",
|
|
47
79
|
markdown: { content: withTagHeader(target, markdown) },
|
|
48
80
|
});
|
|
49
81
|
};
|
|
50
|
-
export const startScheduler = ({ client,
|
|
51
|
-
const fire = async (
|
|
82
|
+
export const startScheduler = ({ client, registry, log, inject, cwdOf, fallbackTarget }) => {
|
|
83
|
+
const fire = async (t) => {
|
|
84
|
+
const target = t.target || fallbackTarget();
|
|
52
85
|
if (!inject) {
|
|
53
|
-
log.warn({ id:
|
|
86
|
+
log.warn({ id: t.id, target }, "scheduled task skipped: not in mirror mode");
|
|
54
87
|
return;
|
|
55
88
|
}
|
|
89
|
+
if (!target) {
|
|
90
|
+
log.warn({ id: t.id }, "scheduled task skipped: no target");
|
|
91
|
+
return;
|
|
92
|
+
}
|
|
93
|
+
// gate: 有活才继续。没活是**静默**的 —— 它存在的全部意义就是不惊动任何人。
|
|
94
|
+
const st = registry.stateOf(t.id);
|
|
95
|
+
const v = t.hasGate
|
|
96
|
+
? await runGate({
|
|
97
|
+
file: t.file,
|
|
98
|
+
task: { id: t.id, target, cwd: cwdOf?.(target) ?? "" },
|
|
99
|
+
state: st.memo ?? {},
|
|
100
|
+
timeoutSec: t.gateTimeoutSec,
|
|
101
|
+
log,
|
|
102
|
+
})
|
|
103
|
+
: { go: true, vars: {}, logs: [] };
|
|
104
|
+
if (v.logs.length)
|
|
105
|
+
log.info({ id: t.id, logs: v.logs }, "gate log");
|
|
106
|
+
if (!v.go) {
|
|
107
|
+
// 没活是静默的, 但**炸了**必须出声: gate 一坏这条定时就再也不放枪了, 而它
|
|
108
|
+
// 每一轮的沉默看起来和"今天没活"一模一样 —— 最坏的失败是看不见的失败。
|
|
109
|
+
// 只在由好转坏的那一次说, 否则一个坏 gate 会按间隔刷屏。
|
|
110
|
+
const first = v.error && st.lastGate !== "error";
|
|
111
|
+
registry.patchState(t.id, {
|
|
112
|
+
lastGate: v.error ? "error" : "skip",
|
|
113
|
+
lastGateAt: Date.now(),
|
|
114
|
+
lastError: v.error,
|
|
115
|
+
...(v.state ? { memo: v.state } : {}),
|
|
116
|
+
});
|
|
117
|
+
log.info({ id: t.id, err: v.error }, v.error ? "task gate errored, holding fire" : "task gate said no, holding fire");
|
|
118
|
+
if (first) {
|
|
119
|
+
await announce(client, target, `⏰ 定时任务 \`${t.id}\` 的 gate 出错, 本轮未放枪 (下次照常重试):\n> ${v.error.split("\n")[0].slice(0, 200)}\n修它: \`${t.file}\``)
|
|
120
|
+
.catch(() => { });
|
|
121
|
+
}
|
|
122
|
+
return;
|
|
123
|
+
}
|
|
124
|
+
registry.patchState(t.id, {
|
|
125
|
+
lastGate: "go", lastGateAt: Date.now(), lastError: undefined,
|
|
126
|
+
...(v.state ? { memo: v.state } : {}),
|
|
127
|
+
});
|
|
128
|
+
const prompt = interpolate(t.prompt, v.vars);
|
|
56
129
|
// 先 announce 后注入: 被唤醒的 wizard 接下来在群里说的话才有出处, 否则群里凭空
|
|
57
130
|
// 冒出一轮对话, 没人知道是谁点的火。
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
131
|
+
const how = t.fresh ? " · 新建 wizard 执行" : "";
|
|
132
|
+
await announce(client, target, `⏰ **定时任务** · ${describeTrigger(t.trigger)}${how}\n> ${prompt.split("\n")[0].slice(0, 120)}`)
|
|
133
|
+
.catch((e) => log.warn({ id: t.id, err: e.message }, "task announce failed"));
|
|
134
|
+
const r = await inject(target, prompt, { taskId: t.id, fresh: t.fresh });
|
|
135
|
+
log.info({ id: t.id, target, ok: r.ok, reason: r.reason }, "scheduled task fired");
|
|
136
|
+
if (!r.ok)
|
|
137
|
+
await announce(client, target, `⏰ 定时任务注入失败:${r.reason ?? "unknown"}`).catch(() => { });
|
|
65
138
|
};
|
|
66
139
|
const tick = async () => {
|
|
67
140
|
const now = new Date();
|
|
68
|
-
const due =
|
|
141
|
+
const due = registry.list().filter((t) => t.enabled && isDue(t.trigger, now, sinceOf(registry.stateOf(t.id))));
|
|
69
142
|
if (!due.length)
|
|
70
143
|
return;
|
|
71
144
|
const firedAt = now.getTime();
|
|
72
|
-
const
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
.map((s) => (fired.has(s.id) ? { ...s, lastFired: firedAt } : s))
|
|
76
|
-
.filter((s) => !(s.when.kind === "once" && s.lastFired));
|
|
77
|
-
persist(cfg, sourcePath);
|
|
78
|
-
for (const s of due) {
|
|
145
|
+
for (const t of due)
|
|
146
|
+
registry.patchState(t.id, { lastFired: firedAt });
|
|
147
|
+
for (const t of due) {
|
|
79
148
|
try {
|
|
80
|
-
await fire(
|
|
149
|
+
await fire(t);
|
|
81
150
|
}
|
|
82
151
|
catch (e) {
|
|
83
|
-
log.error({ id:
|
|
152
|
+
log.error({ id: t.id, err: e.message }, "scheduled fire failed");
|
|
84
153
|
}
|
|
154
|
+
// once 放完这一枪就没有下一枪了, 留着只会让列表越来越脏。
|
|
155
|
+
if (t.trigger.clock.kind === "once")
|
|
156
|
+
registry.remove(t.id);
|
|
85
157
|
}
|
|
86
158
|
};
|
|
87
159
|
const timer = setInterval(() => { void tick(); }, 20_000);
|
package/dist/daemon/tasks.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tasks.js","sourceRoot":"","sources":["../../daemon/tasks.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"tasks.js","sourceRoot":"","sources":["../../daemon/tasks.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
// 群记忆 / 工作区记忆: wizard 自己的 memory 之外的两份**共享**记忆。
|
|
2
|
+
//
|
|
3
|
+
// 一个 wizard 的 memory 跟着它自己走 (wizards.json), 可很多东西不属于某一个 wizard:
|
|
4
|
+
// 「这个群里人习惯先出方案再动手」属于这个群, 「这个仓库没有测试、reload 要先 build」
|
|
5
|
+
// 属于这个工作区。它们各存一份 markdown, 任何 wizard 出生时两份都注进宪章 —— 于是
|
|
6
|
+
// 一个新来的不必被人再教一遍。是 md 而不是 json: 人也会直接打开改它。
|
|
7
|
+
//
|
|
8
|
+
// ~/.wezard/memory/chats/<base>.md
|
|
9
|
+
// ~/.wezard/memory/workspaces/<cwd 编码>.md
|
|
10
|
+
//
|
|
11
|
+
// 读写失败一律吞掉: 记忆是锦上添花, 读不到就当没有, 写不进就回报失败, 都不该拖垮 spawn。
|
|
12
|
+
import { appendFileSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
|
|
13
|
+
import { dirname, join } from "node:path";
|
|
14
|
+
import { expandHome } from "../shared/paths.js";
|
|
15
|
+
/** 任意 key → 一个安全的文件名。`chat:wr4…` → `chat_wr4…`, `/Users/a/b` → `-Users-a-b`。 */
|
|
16
|
+
const fileKey = (k) => k.trim().replace(/\/+$/, "").replace(/\//g, "-").replace(/[^\p{L}\p{N}_.-]+/gu, "_").slice(0, 200) || "_";
|
|
17
|
+
/** 记忆根目录: stateDir 的兄弟 (`~/.wezard/state` → `~/.wezard/memory`)。 */
|
|
18
|
+
export const memoryRoot = (stateDir) => join(dirname(expandHome(stateDir)), "memory");
|
|
19
|
+
export const memoryPath = (stateDir, scope, key) => join(memoryRoot(stateDir), scope === "chat" ? "chats" : "workspaces", `${fileKey(key)}.md`);
|
|
20
|
+
/** 整份读出 (去掉首尾空白); 不存在 / 读失败 = ""。 */
|
|
21
|
+
export const readMemory = (path) => {
|
|
22
|
+
try {
|
|
23
|
+
return readFileSync(path, "utf8").trim();
|
|
24
|
+
}
|
|
25
|
+
catch {
|
|
26
|
+
return "";
|
|
27
|
+
}
|
|
28
|
+
};
|
|
29
|
+
/** 追加一条 `- note`。 */
|
|
30
|
+
export const appendMemory = (path, note) => {
|
|
31
|
+
try {
|
|
32
|
+
mkdirSync(dirname(path), { recursive: true });
|
|
33
|
+
appendFileSync(path, `- ${note.replace(/\s*\n\s*/g, " ").trim()}\n`);
|
|
34
|
+
return true;
|
|
35
|
+
}
|
|
36
|
+
catch {
|
|
37
|
+
return false;
|
|
38
|
+
}
|
|
39
|
+
};
|
|
40
|
+
/** 按子串删掉匹配的行 (模型记得大意, 记不住原文), 返回删了几条。 */
|
|
41
|
+
export const forgetMemory = (path, needle) => {
|
|
42
|
+
const cur = readMemory(path);
|
|
43
|
+
if (!cur || !needle)
|
|
44
|
+
return 0;
|
|
45
|
+
const lines = cur.split("\n");
|
|
46
|
+
const kept = lines.filter((l) => !l.includes(needle));
|
|
47
|
+
if (kept.length === lines.length)
|
|
48
|
+
return 0;
|
|
49
|
+
try {
|
|
50
|
+
writeFileSync(path, kept.length ? `${kept.join("\n")}\n` : "");
|
|
51
|
+
return lines.length - kept.length;
|
|
52
|
+
}
|
|
53
|
+
catch {
|
|
54
|
+
return 0;
|
|
55
|
+
}
|
|
56
|
+
};
|
|
57
|
+
//# sourceMappingURL=wizard-memory.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"wizard-memory.js","sourceRoot":"","sources":["../../daemon/wizard-memory.ts"],"names":[],"mappings":"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"}
|
package/dist/daemon/wizard.js
CHANGED
|
@@ -13,22 +13,41 @@
|
|
|
13
13
|
// 本模块只有两类东西: 一个写盘的注册表 (唯一副作用), 和一堆把记录渲染成文字的
|
|
14
14
|
// 纯函数。真正的动作 (spawn / inject / kill) 全在 mirror-bridge, 这里一个都不做。
|
|
15
15
|
import { loadJsonMap } from "../shared/json-map-store.js";
|
|
16
|
-
import { tagOfKey } from "../shared/session-label.js";
|
|
16
|
+
import { normalizeTag, stripSigil, tagOfKey, uniqueTag } from "../shared/session-label.js";
|
|
17
17
|
const MEMORY_MAX = 60;
|
|
18
18
|
const NOTE_MAX = 600;
|
|
19
19
|
const blank = (target) => ({ target, name: "", description: "", bornAt: Date.now(), memory: [] });
|
|
20
|
+
const foldName = (n) => stripSigil(n).toLowerCase();
|
|
21
|
+
/** `want` 规整成合法名字, 再避开 `others` 已占的 (大小写不敏感)。空 → "wizard"。 */
|
|
22
|
+
export const pickName = (want, others) => {
|
|
23
|
+
const taken = new Set(others.map(foldName).filter(Boolean));
|
|
24
|
+
const base = normalizeTag(want) || "wizard";
|
|
25
|
+
const n = uniqueTag(base.toLowerCase(), taken);
|
|
26
|
+
// uniqueTag 在折叠后的空间里找空位; 结果按原大小写回填前缀, 只追加 `-N`。
|
|
27
|
+
return n === base.toLowerCase() ? base : `${base.slice(0, 29)}${n.slice(Math.min(base.length, 29))}`;
|
|
28
|
+
};
|
|
20
29
|
/** 写穿式单文件存储, 与 mirror-store 同款 —— 这是运行时状态, 不是用户手写配置,
|
|
21
30
|
* 所以躺在 stateDir 而不是 config.jsonc。 */
|
|
22
31
|
export const loadWizardStore = (filePath) => {
|
|
23
32
|
const db = loadJsonMap(filePath);
|
|
33
|
+
const all = () => Object.values(db.all());
|
|
34
|
+
const upsert = (t, patch) => {
|
|
35
|
+
const next = { ...(db.get(t) ?? blank(t)), ...patch, target: t };
|
|
36
|
+
return db.set(t, { ...next, memory: next.memory.slice(-MEMORY_MAX).map((m) => m.slice(0, NOTE_MAX)) });
|
|
37
|
+
};
|
|
38
|
+
const namesExcept = (t) => all().filter((w) => w.target !== t).map((w) => w.name);
|
|
39
|
+
const rename = (t, want) => upsert(t, { name: pickName(want, namesExcept(t)) }).name;
|
|
24
40
|
return {
|
|
25
41
|
get: db.get,
|
|
26
|
-
|
|
27
|
-
const
|
|
28
|
-
return
|
|
42
|
+
byName: (n) => {
|
|
43
|
+
const k = foldName(n);
|
|
44
|
+
return k ? all().find((w) => foldName(w.name) === k) : undefined;
|
|
29
45
|
},
|
|
46
|
+
claim: (t, want) => db.get(t)?.name || rename(t, want),
|
|
47
|
+
rename,
|
|
48
|
+
upsert,
|
|
30
49
|
drop: db.drop,
|
|
31
|
-
all
|
|
50
|
+
all,
|
|
32
51
|
};
|
|
33
52
|
};
|
|
34
53
|
// 进程内唯一的注册表。daemon 启动时绑一次, 之后任何模块都读得到 —— IM 侧的
|
|
@@ -38,17 +57,25 @@ let bound;
|
|
|
38
57
|
export const bindWizardStore = (store) => (bound = store);
|
|
39
58
|
export const wizardStore = () => bound;
|
|
40
59
|
// ── 纯推导 ────────────────────────────────────────────────────────────
|
|
41
|
-
/**
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
export const wizardName = (rec, chatName, target) =>
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
const
|
|
49
|
-
if (
|
|
50
|
-
return
|
|
51
|
-
|
|
60
|
+
/** 一个 target 的默认名: 默认会话取聊天名, 分身取 slot id。去重交给 claim。 */
|
|
61
|
+
export const defaultNameOf = (chatName, target) => tagOfKey(target) || chatName;
|
|
62
|
+
/** 名字: 名册里落定的 > 默认名。只读推导, 不写盘 —— 需要落定用 store.claim。 */
|
|
63
|
+
export const wizardName = (rec, chatName, target) => (rec?.name ?? "").trim() || defaultNameOf(chatName, target);
|
|
64
|
+
/** 名字落定: 名册有就用; 没有且推得出默认名就 claim (写盘去重); 都没有退回 slot id。
|
|
65
|
+
* 推不出 (默认会话所在的聊天还没名字) 时不 claim —— 否则它会永久落成 `wizard-N`。 */
|
|
66
|
+
export const settleName = (store, chatName, target) => {
|
|
67
|
+
const have = store?.get(target)?.name;
|
|
68
|
+
if (have)
|
|
69
|
+
return have;
|
|
70
|
+
const want = defaultNameOf(chatName, target);
|
|
71
|
+
return store && want ? store.claim(target, want) : want;
|
|
72
|
+
};
|
|
73
|
+
/** 一次性迁移/补名: 默认会话先挑 (聊天名归它), 其余按出生先后。 */
|
|
74
|
+
export const settleAll = (store, targets, chatNameOf) => {
|
|
75
|
+
const born = (t) => store.get(t)?.bornAt ?? Number.MAX_SAFE_INTEGER;
|
|
76
|
+
[...new Set(targets)]
|
|
77
|
+
.sort((a, b) => Number(!!tagOfKey(a)) - Number(!!tagOfKey(b)) || born(a) - born(b))
|
|
78
|
+
.forEach((t) => settleName(store, chatNameOf(t), t));
|
|
52
79
|
};
|
|
53
80
|
/** 直系分身。 */
|
|
54
81
|
export const childrenOf = (all, target) => all.filter((w) => w.parent === target);
|
|
@@ -59,69 +86,90 @@ export const ancestorsOf = (all, target) => {
|
|
|
59
86
|
return walk(byTarget.get(target)?.parent, []);
|
|
60
87
|
};
|
|
61
88
|
const bullet = (xs) => xs.map((x) => `- ${x}`).join("\n");
|
|
62
|
-
const
|
|
89
|
+
const addr = (b) => `.${b.address || b.name || "?"}`;
|
|
90
|
+
const nameLine = (b) => `\`${addr(b)}\`${b.description ? ` · ${b.description}` : ""}${b.cwd ? ` · ${b.cwd}` : ""}`;
|
|
63
91
|
/** 开局宪章 —— spawn 时作为 `--append-system-prompt` 压进进程。
|
|
64
92
|
* 它回答四件事, 每一件都是"会话自己没法从对话里知道"的:
|
|
65
|
-
* 我是谁 /
|
|
93
|
+
* 我是谁 / 我住在哪、周围有谁 / 我有哪些能力 / 公开频道与私聊该怎么说话。 */
|
|
66
94
|
export const renderCharter = (a) => {
|
|
95
|
+
const me = a.self.address || a.self.name;
|
|
67
96
|
const parts = [
|
|
68
97
|
"# 你是一个 wizard",
|
|
69
98
|
"",
|
|
70
99
|
"你不是一次性的助手进程。你是 wezard 架在企业微信与本机 agent CLI 之间的一个**常驻角色**:",
|
|
71
|
-
"
|
|
100
|
+
"有一个全局唯一的名字、一个工作区、职责和记忆, 能生分身、能和别的 wizard 私聊, 也能在群里当着人说话。",
|
|
72
101
|
"下面是你的身份, 它随你这个进程终身有效 —— 即使 `/clear` 清空了对话, 这段话仍在。",
|
|
73
102
|
"",
|
|
74
103
|
"## 我是谁",
|
|
75
104
|
bullet([
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
`所在聊天: ${a.chat ? `**${a.chat}**` : "(还没有名字 —— 它会在第一次被用到时按工作区自动补上; 想要个更好的名字就 name_chat)"} \`${a.principal}\``,
|
|
105
|
+
`名字 / 地址: **\`.${me || "(未命名)"}\`** —— 全机唯一。人在任何群里写 \`.${me}\` 就叫到你; 别的 wizard 用 \`${me}\` 作为 send_peer 的 \`name\``,
|
|
106
|
+
`出生的群 (home): ${a.chat ? `**${a.chat}**` : "(还没有名字 —— 第一次被用到时按工作区自动补上)"} \`${a.principal}\``,
|
|
79
107
|
`工作区: \`${a.self.cwd || "(未设置)"}\``,
|
|
80
108
|
`职责: ${a.self.description || "(未写 —— 用 wizard_identity 写一句, 别人靠它决定该不该找你)"}`,
|
|
81
109
|
a.parent
|
|
82
|
-
?
|
|
110
|
+
? a.inherited
|
|
111
|
+
? `出身: **\`${addr(a.parent)}\`** 的分身 —— 从它的 session 节点 fork 而来, **你继承了它当时的全部上下文**(它读过的文件/文档你开局就有)`
|
|
112
|
+
: `出身: **\`${addr(a.parent)}\`** 生的子 wizard —— 白板起步, 不继承它的上下文`
|
|
83
113
|
: "出身: 本聊天的原生 wizard",
|
|
84
114
|
]),
|
|
85
115
|
"",
|
|
86
116
|
];
|
|
117
|
+
// 新聊天的第一个 wizard 落在默认兜底目录里 —— 那不是人选的, 只是还没人说过。与其
|
|
118
|
+
// 让它在错的目录里把活干完, 不如开工前先问一句: 一句话的代价, 换掉一次重来。
|
|
119
|
+
if (a.cwdUnconfirmed) {
|
|
120
|
+
parts.push("> ⚠️ 上面这个工作区是**没人选过的默认兜底目录**, 不是人指定的。", "> 所以**开工前先问一句**: 要在哪个项目目录下干活?", "> 给了路径 → `set_workspace({cwd})` (当场换目录重开; 这一轮上下文会没, 让他把活再说一遍)。", "> 说就用这个 / 不用换 → `set_workspace({keep:true})` 记一笔, 此后谁都不会再问。", "> 只问这一次 —— 他不答就照这个目录干, 别反复追问。", "");
|
|
121
|
+
}
|
|
87
122
|
if (a.memory.length > 0) {
|
|
88
123
|
parts.push("## 我的记忆", "这些是你自己写下的、要跨会话活下来的东西:", bullet(a.memory), "");
|
|
89
124
|
}
|
|
125
|
+
if (a.chatMemory) {
|
|
126
|
+
parts.push("## 本群记忆", "这个群里所有 wizard 共享的记忆 (`wizard_remember({scope:\"chat\"})` 追加; 人也会直接改):", a.chatMemory, "");
|
|
127
|
+
}
|
|
128
|
+
if (a.workspaceMemory) {
|
|
129
|
+
parts.push("## 本工作区记忆", "在这个目录下干活的所有 wizard 共享的记忆 (`wizard_remember({scope:\"workspace\"})` 追加; 人也会直接改):", a.workspaceMemory, "");
|
|
130
|
+
}
|
|
90
131
|
if (a.siblings.length > 0) {
|
|
91
|
-
parts.push("##
|
|
132
|
+
parts.push("## 出生时同群的 wizard", bullet(a.siblings.map(nameLine)), "(这只是出生那一刻的快照。此后谁来了、谁收工了、谁改了职责, 会以一行 system-reminder", "挂在下一条进到你这儿的消息尾巴上 —— 不必去问。要当下完整的名册仍然是 `wizard_roster`; 名字全局唯一, 别的群的 wizard 一样叫得到。)", "");
|
|
92
133
|
}
|
|
93
134
|
parts.push("## 我能做什么 (MCP `wezard`)", bullet([
|
|
94
135
|
"`wizard_whoami` 我是谁、上下文用了多少、我的分身有哪些",
|
|
95
|
-
"`wizard_identity`
|
|
96
|
-
"`wizard_roster` 全部 wizard 与 clone:
|
|
97
|
-
"`spawn_clone` 生一个分身 —— `inherit:true` 让它继承我此刻的上下文, `inherit:false` 给它一张白纸; `model` 给它挑模型 (跑腿的活给 haiku, 要判断的给 opus); 分身还能再生分身",
|
|
136
|
+
"`wizard_identity` 改名字 / 写职责 (名字全局唯一, 撞名会自动加 `-N` 后缀并告诉你最终名字)",
|
|
137
|
+
"`wizard_roster` 全部 wizard 与 clone: 名字、home 群、工作区、职责、模型、忙闲、家谱",
|
|
138
|
+
"`spawn_clone` 生一个分身 —— `inherit:true` 让它继承我此刻的上下文, `inherit:false` 给它一张白纸; `name` 给它起名 (全局唯一); `model` 给它挑模型 (跑腿的活给 haiku, 要判断的给 opus); 分身还能再生分身",
|
|
98
139
|
"`stop_wizard` 打断或终结一个分身/wizard (活干完了就收掉它)",
|
|
99
140
|
"`open_job` / `close_job` / `list_jobs` 一次要派出两个以上分身时的**工单**: 群里只出开工/收工两条气泡, 收工时整批回收临时分身",
|
|
100
|
-
"`wizard_remember` 写一条跨会话的记忆",
|
|
141
|
+
"`wizard_remember` 写一条跨会话的记忆 —— `scope` 选 `self` (我自己的) / `chat` (本群共享) / `workspace` (本工作区共享)",
|
|
101
142
|
"`wizard_handoff_self` 上下文快满时自己原地交接重开",
|
|
102
|
-
"`send_peer` 跟别的 wizard
|
|
103
|
-
"`wait_peer` 等它干完 —— 派了一**批**活就用 `
|
|
104
|
-
"`notify`
|
|
105
|
-
"`schedule_task`
|
|
143
|
+
"`send_peer` 跟别的 wizard 说话, **默认私聊**; `public:true` 则在群里公开说 (见下) · 派活给一个正在忙的同伴用 `when:\"idle\"` · `peek_peer` 看它在干嘛 · `list_peers` 看同群有谁",
|
|
144
|
+
"`wait_peer` 等它干完 —— 派了一**批**活就用 `names` 一次等一组 (`need` 决定满几个就返回), 别一个一个等",
|
|
145
|
+
"`notify` 把一段话贴进某个群给**人**看 (省略 `to` 就是你这一轮所在的群) —— 和 send_peer 相反, 它不驱动任何 agent",
|
|
146
|
+
"`schedule_task` 排一个到点自动执行的活 (「每个工作日晚上9:30 …」) —— 日程归在你名下; 默认到点**新起一个白板 wizard** 去干, 干完自动收掉; 只有明说「在 .foo 里继续」才用 `name` 点名已有的那个 · `list_tasks` / `cancel_task`",
|
|
106
147
|
"`set_workspace` 换工作区 · `name_chat` 给聊天起名 · `list_chats` 看别的聊天",
|
|
107
148
|
"`run_agent_graph` 把多个 wizard 串成一条会循环的流水线",
|
|
108
149
|
]), "", "## 怎么干活: 编排", "遇到一组「共享同一批上下文」的任务, 不要自己一件件做完, 也不要让每个分身各读一遍材料。", "**控制流在你手里** —— 没有别的调度器替你跑这件事: 你自己分路、自己派、自己等、自己汇总。", bullet([
|
|
109
150
|
"先在自己这里把**公共材料**读进上下文 (规范、目录结构、关键文件)",
|
|
110
151
|
"要派出两个以上的分身就先 `open_job(标题, 计划)` 拿一个工单 id —— 之后每个 `spawn_clone` / `send_peer` 都带上 `job`",
|
|
111
152
|
"`spawn_clone({inherit:true, task})` 出需要的分身: 它们开局就带着这些材料, 只需告诉它各自那一份差异; 活写进 `task` 省一次往返",
|
|
153
|
+
"撞名 (`spawn_clone` 409) 别顺手 `send_peer` 糊弄过去: 响应里的 `alive`/`busy`/`idleForMs` 已经说清那是真在干活还是冷绑定。真活着就换个名字重新生, 别把不相关的活塞给一个已经有职责的 wizard; 冷绑定才值得复用, 但复用前先 `stop_wizard({mode:\"end\"})` 把它收掉腾出名字, 再用同一个名字重新 spawn —— 拿到干净的上下文",
|
|
154
|
+
"地址永远是名字本身 (`fix` 或 `.fix`), 全局唯一, 不分群; 永远别自己拼 key —— roster / 409 里的 `address` 原样传回来",
|
|
112
155
|
"派活时要求它**把结论收口成一行** `RESULT: …` (交付物写进文件就回传路径) —— `wait_peer` 会把这一行单独摘进 `result`, 免得你从八百字散文里找结论",
|
|
113
|
-
"一次 `wait_peer({
|
|
156
|
+
"一次 `wait_peer({names:[…]})` 把它们**一起**等回来。它们本来就在并行干活: 一个一个等, 墙钟是所有人之和; 一起等只花最慢那一个的时间 (`need` 可以让你先处理最先完事的那几个)",
|
|
114
157
|
"汇总完 `close_job(summary)` —— 结论发进群, 为这个工单生出来的分身整批回收。要反复迭代到收敛则用 `run_agent_graph`",
|
|
115
|
-
]), "分身是有成本的 (一个 tmux pane + 一份上下文), 而且名下同时活着的分身有上限 ——", "任务少于两三件时自己做完更快; 干完了就收, 别让上一批堵住下一批。", "", "## 怎么说话:
|
|
158
|
+
]), "分身是有成本的 (一个 tmux pane + 一份上下文), 而且名下同时活着的分身有上限 ——", "任务少于两三件时自己做完更快; 干完了就收, 别让上一批堵住下一批。", "", "## 怎么说话: 群是公开频道, wizard 之间默认私聊", "有人在的群 (以及人与你的单聊) 是**公开频道**: 人从哪个群叫你, 你这一轮的回复就发回哪个群。", "wizard 之间的 `send_peer` **默认是私聊** —— 不出任何群气泡, 只记在双方的 rolepage (每个角色视角的聊天记录页) 里;", "对方私聊轮的回复也不进群, 你用 `wait_peer` 取。要不要公开**由你判断**:", bullet([
|
|
159
|
+
"**需要人知道的, 或本就该当着人讨论的** (关键决策、给人的结论、需要人拍板的分歧、人点名要看的协作) → `send_peer({public:true})`: 群里出 `.你 → .它` 的气泡, 它那一轮的回复也发进这个群",
|
|
160
|
+
"**过程性的往来** (派活细节、催进度、交换中间产物、对齐接口) → 私聊, 这是默认",
|
|
161
|
+
"**只是告诉人一件事**, 不需要驱动谁 → `notify`",
|
|
162
|
+
]), "人看得见群里的公开消息和工单的开工/收工, 看不见私聊 (要看得去 rolepage)。所以:", bullet([
|
|
116
163
|
"**分清对象**: 对人说话 = 你的正常回复; 对 wizard 说话 = `send_peer`。别把派给分身的指令写进给人的回复里。",
|
|
117
|
-
"**不要复述**:
|
|
164
|
+
"**不要复述**: 公开的往来人已经看见了; 私聊的结论人需要知道时, 用你自己的话收口给人, 别把对方原话再念一遍。收到消息不必回「收到」。",
|
|
118
165
|
"**对 wizard 直说**: 不用寒暄、不用引用原文、不用客套。要什么、给什么、结论是什么, 一句话讲完。",
|
|
119
166
|
"**不要替别人开口**: 分身该做的事派给它、等它, 不要自己猜它会说什么然后替它答。",
|
|
120
167
|
"**对人要收口**: 人关心的是进展和结论, 不是你们之间的每一次往返。",
|
|
121
168
|
]), "", "## 自我管理", bullet([
|
|
122
169
|
"上下文快满 (`wizard_whoami` 的 contextTokens) → 自己调 `wizard_handoff_self`, 把工作压成简报原地重开。",
|
|
123
170
|
"要换项目目录 → 自己调 `set_workspace`, 不必让人去敲命令。",
|
|
124
|
-
"
|
|
171
|
+
"职责为空 → 自己调 `wizard_identity` 补上; 名字就是别人喊你的那个词。",
|
|
172
|
+
"学到了属于这个群 / 这个仓库、而不只属于你的东西 → `wizard_remember` 选对 `scope`, 下一个来的 wizard 开局就知道。",
|
|
125
173
|
]));
|
|
126
174
|
return parts.filter((p) => p !== undefined).join("\n");
|
|
127
175
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"wizard.js","sourceRoot":"","sources":["../../daemon/wizard.ts"],"names":[],"mappings":"AAAA,2BAA2B;AAC3B,EAAE;AACF,sDAAsD;AACtD,0CAA0C;AAC1C,8DAA8D;AAC9D,+CAA+C;AAC/C,qBAAqB;AACrB,EAAE;AACF,sDAAsD;AACtD,4DAA4D;AAC5D,2DAA2D;AAC3D,EAAE;AACF,4CAA4C;AAC5C,+DAA+D;AAC/D,OAAO,EAAE,WAAW,EAAE,MAAM,6BAA6B,CAAC;AAC1D,OAAO,EAAE,QAAQ,EAAE,MAAM,4BAA4B,CAAC;
|
|
1
|
+
{"version":3,"file":"wizard.js","sourceRoot":"","sources":["../../daemon/wizard.ts"],"names":[],"mappings":"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"}
|