@clawos-dev/clawd 0.2.401 → 0.2.403
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/dist/cli.cjs +100 -9
- package/dist/dispatch/mcp-server.cjs +36 -1
- package/dist/share-md-viewer-error.html +1 -1
- package/dist/share-md-viewer.html +1 -1
- package/dist/share-ui/assets/{guest-CkFU2bIi.js → guest-vUOVp3oA.js} +139 -139
- package/dist/share-ui/assets/guest-xzm4Oo0s.css +32 -0
- package/dist/share-ui/guest.html +2 -2
- package/package.json +1 -1
- package/dist/share-ui/assets/guest-BHvC4vAI.css +0 -32
package/dist/cli.cjs
CHANGED
|
@@ -6692,6 +6692,21 @@ var init_topic = __esm({
|
|
|
6692
6692
|
TopicLineMetaSchema = external_exports.object({
|
|
6693
6693
|
rejectCount: external_exports.number().int().min(0),
|
|
6694
6694
|
accepted: external_exports.boolean().default(false),
|
|
6695
|
+
/**
|
|
6696
|
+
* 该线在本话题内的**序号**,daemon 按建线先后顺序发,从 1 起。
|
|
6697
|
+
*
|
|
6698
|
+
* 存在的理由只有一个:老板说「第 2 条线」和 Master 说「线2」得指同一条。所以它必须
|
|
6699
|
+
* **稳定且不复用**——删掉第 2 条后新建的线拿 4 而不是 2,否则昨天说的号今天指向别的线,
|
|
6700
|
+
* 序号就没有价值了。发号点见 topic-store.claimLineOrdinal。
|
|
6701
|
+
*
|
|
6702
|
+
* 早先这个号是 UI 从 lineId 字符串里 parse 的(`line-<N>-<slug>`),等于把序号语义
|
|
6703
|
+
* 寄生在 Master 随手起的名字上:Master 用语义命名(`line-channel-fix`)就 parse 不出,
|
|
6704
|
+
* sidebar 整个不显示号。序号的产生端必须是 daemon。
|
|
6705
|
+
*
|
|
6706
|
+
* optional 而非 default:store 不按 schema parse(见 topic-store),存量 lineMeta
|
|
6707
|
+
* 里没有这个字段,读侧一律 `?? null`,回填由 `topic:get` 的发号 pass 幂等补上。
|
|
6708
|
+
*/
|
|
6709
|
+
ordinal: external_exports.number().int().min(1).optional(),
|
|
6695
6710
|
/**
|
|
6696
6711
|
* Master 在 watcher 判 fail 的情况下仍判合格的次数。
|
|
6697
6712
|
*
|
|
@@ -6716,6 +6731,19 @@ var init_topic = __esm({
|
|
|
6716
6731
|
activity: external_exports.array(TopicActivityEntrySchema),
|
|
6717
6732
|
/** lineId -> 线级元数据 */
|
|
6718
6733
|
lineMeta: external_exports.record(TopicLineMetaSchema),
|
|
6734
|
+
/**
|
|
6735
|
+
* 线号水位:下一条线该拿的号。发一个加一,**只增不减**。
|
|
6736
|
+
*
|
|
6737
|
+
* 为什么是话题上的一个独立字段,而不是「现有 lineMeta 里的最大号 + 1」现算:现算的水位
|
|
6738
|
+
* 跟着现存线数走,删掉最大号那条线水位就退,下一条新线会**捡回那个号**。老板原话:
|
|
6739
|
+
* 「删了线,已经标记的线的序号不能变吧,要不然留档的记录不都坏了么」——号对不上只是难用,
|
|
6740
|
+
* 号能对上、却对到了另一条线(流水里「#3 判合格」后来指向一条新线)是把留档直接读坏。
|
|
6741
|
+
* 所以不变式有两条:**已发的号永不改**、**号永不复用**,后者必须与现存线数彻底脱钩。
|
|
6742
|
+
*
|
|
6743
|
+
* optional 而非 default:store 不按 schema parse(见 topic-store),存量话题没有这个
|
|
6744
|
+
* 字段,读盘时按「现有最大号 + 1」一次性归一(不能从 1 重开,否则现有的 #1 #2 会被复用)。
|
|
6745
|
+
*/
|
|
6746
|
+
nextLineOrdinal: external_exports.number().int().min(1).optional(),
|
|
6719
6747
|
state: TopicStateSchema,
|
|
6720
6748
|
createdAt: external_exports.string().min(1),
|
|
6721
6749
|
updatedAt: external_exports.string().min(1)
|
|
@@ -6730,7 +6758,14 @@ var init_topic = __esm({
|
|
|
6730
6758
|
acceptance: external_exports.array(external_exports.string()),
|
|
6731
6759
|
rejectCount: external_exports.number().int().min(0),
|
|
6732
6760
|
/** 已被 Master 判定合格(`topic:accept`)。UI 的「合格」态靠它,不是猜的 */
|
|
6733
|
-
accepted: external_exports.boolean()
|
|
6761
|
+
accepted: external_exports.boolean(),
|
|
6762
|
+
/**
|
|
6763
|
+
* 线号(见 TopicLineMetaSchema.ordinal)。UI 直接渲染,**不再从 lineId 猜**。
|
|
6764
|
+
*
|
|
6765
|
+
* nullable 而非必填:joinLines 是纯函数,拿到的 lineMeta 里可能还没发过号(发号 pass
|
|
6766
|
+
* 在 handler 侧)。走 `topic:get` 出去的线一律已发号,null 只在纯函数被单独调用时出现。
|
|
6767
|
+
*/
|
|
6768
|
+
ordinal: external_exports.number().int().min(1).nullable()
|
|
6734
6769
|
});
|
|
6735
6770
|
TopicListArgsSchema = external_exports.object({ channelId: external_exports.string().min(1) });
|
|
6736
6771
|
TopicGetArgsSchema = external_exports.object({
|
|
@@ -52657,6 +52692,10 @@ var PersonaDispatchManager = class {
|
|
|
52657
52692
|
...args.taskBrief ? { taskBrief: args.taskBrief } : {},
|
|
52658
52693
|
...args.meta ? { meta: args.meta } : {}
|
|
52659
52694
|
});
|
|
52695
|
+
const lineId = args.meta?.["lineId"];
|
|
52696
|
+
if (typeof lineId === "string" && lineId) {
|
|
52697
|
+
this.deps.onLineClaimed?.({ sourceSessionId: args.sourceSessionId, lineId });
|
|
52698
|
+
}
|
|
52660
52699
|
return { dispatchId };
|
|
52661
52700
|
}
|
|
52662
52701
|
get(dispatchId) {
|
|
@@ -52908,19 +52947,40 @@ function createTopicStore(deps) {
|
|
|
52908
52947
|
t.updatedAt = new Date(deps.now()).toISOString();
|
|
52909
52948
|
};
|
|
52910
52949
|
const lineMetaOf = (t, lineId) => t.lineMeta[lineId] ??= { rejectCount: 0, accepted: false, overrideCount: 0 };
|
|
52950
|
+
const ensureOrdinalWatermark = (t) => {
|
|
52951
|
+
const floor = Object.values(t.lineMeta).reduce((max, m2) => Math.max(max, m2.ordinal ?? 0), 0) + 1;
|
|
52952
|
+
const w2 = t.nextLineOrdinal;
|
|
52953
|
+
const normalized = typeof w2 === "number" && Number.isSafeInteger(w2) && w2 >= floor ? w2 : floor;
|
|
52954
|
+
t.nextLineOrdinal = normalized;
|
|
52955
|
+
return normalized;
|
|
52956
|
+
};
|
|
52911
52957
|
return {
|
|
52912
52958
|
/**
|
|
52913
|
-
*
|
|
52959
|
+
* 读盘后两件归一,**落盘口径不同**:一只改内存(下一次任何写操作自然带出去),
|
|
52960
|
+
* 二补过就立刻回写。理由见各自那段。
|
|
52961
|
+
*
|
|
52962
|
+
* 一、存量 `state: 'archived'` 归成 `'done'`。归档已改由该话题 Master 会话的 `archivedAt`
|
|
52963
|
+
* 承载(spec 2026-08-25-topic-archive-and-pin),`TOPIC_STATES` 随之退掉那一档。json-store
|
|
52964
|
+
* 读盘本身不过 zod,但 `topic:list` 的响应要过 `TopicListResultSchema.parse` —— 留着这个
|
|
52965
|
+
* 值会让**整个频道**的话题列表 parse 失败。
|
|
52914
52966
|
*
|
|
52915
|
-
*
|
|
52916
|
-
*
|
|
52917
|
-
*
|
|
52967
|
+
* 二、补/纠线号水位。放在读盘而不是发号时:水位一旦落后于已发出的号,下一条新线就会捡回
|
|
52968
|
+
* 一个已经写进流水的号,那是「留档被读坏」而不是「少个号」,越早接上越好。
|
|
52969
|
+
*
|
|
52970
|
+
* **补过就立刻固化**(这一条与 archived 那条不同,不能只留在内存里):水位不落盘的话,
|
|
52971
|
+
* 下次启动还得靠 lineMeta 重算,而 lineMeta 一旦丢了最大号那条,重算出来的水位就退,
|
|
52972
|
+
* 退了就把已经发出去的号又发一遍。不变式不能挂在「lineMeta 一直完好」这个外部事实上。
|
|
52973
|
+
* 水位已经合法的话题不算改动,不会因此每次启动都写一次盘。
|
|
52918
52974
|
*/
|
|
52919
52975
|
async load() {
|
|
52920
52976
|
await file.load();
|
|
52977
|
+
let normalized = false;
|
|
52921
52978
|
for (const t of file.all()) {
|
|
52922
52979
|
if (t.state === "archived") t.state = "done";
|
|
52980
|
+
const before = t.nextLineOrdinal;
|
|
52981
|
+
if (ensureOrdinalWatermark(t) !== before) normalized = true;
|
|
52923
52982
|
}
|
|
52983
|
+
if (normalized) file.scheduleFlush();
|
|
52924
52984
|
},
|
|
52925
52985
|
flushNow: file.flushNow,
|
|
52926
52986
|
get,
|
|
@@ -52938,6 +52998,8 @@ function createTopicStore(deps) {
|
|
|
52938
52998
|
acceptanceCriteria: [],
|
|
52939
52999
|
activity: [],
|
|
52940
53000
|
lineMeta: {},
|
|
53001
|
+
// 新话题的第一条线拿 1
|
|
53002
|
+
nextLineOrdinal: 1,
|
|
52941
53003
|
state: "planning",
|
|
52942
53004
|
createdAt: iso,
|
|
52943
53005
|
updatedAt: iso
|
|
@@ -52974,6 +53036,19 @@ function createTopicStore(deps) {
|
|
|
52974
53036
|
file.scheduleFlush();
|
|
52975
53037
|
return t;
|
|
52976
53038
|
},
|
|
53039
|
+
claimLineOrdinal(topicId, lineId) {
|
|
53040
|
+
const t = get(topicId);
|
|
53041
|
+
if (!t) return void 0;
|
|
53042
|
+
const existing = t.lineMeta[lineId]?.ordinal;
|
|
53043
|
+
if (existing !== void 0) return existing;
|
|
53044
|
+
const ordinal = ensureOrdinalWatermark(t);
|
|
53045
|
+
t.nextLineOrdinal = ordinal + 1;
|
|
53046
|
+
const meta = lineMetaOf(t, lineId);
|
|
53047
|
+
meta.ordinal = ordinal;
|
|
53048
|
+
touch(t);
|
|
53049
|
+
file.scheduleFlush();
|
|
53050
|
+
return ordinal;
|
|
53051
|
+
},
|
|
52977
53052
|
bumpReject(topicId, lineId) {
|
|
52978
53053
|
const t = get(topicId);
|
|
52979
53054
|
if (!t) return void 0;
|
|
@@ -62113,7 +62188,7 @@ function computeMethodAccess(args) {
|
|
|
62113
62188
|
}
|
|
62114
62189
|
|
|
62115
62190
|
// src/version.ts
|
|
62116
|
-
var version = "0.2.
|
|
62191
|
+
var version = "0.2.403".length > 0 ? "0.2.403" : "dev";
|
|
62117
62192
|
|
|
62118
62193
|
// src/cli-probe/probe.ts
|
|
62119
62194
|
var fs66 = __toESM(require("fs"), 1);
|
|
@@ -64322,7 +64397,9 @@ function joinLines(records, lineMeta) {
|
|
|
64322
64397
|
status: r.status,
|
|
64323
64398
|
acceptance: Array.isArray(meta.acceptance) ? meta.acceptance.map(String) : [],
|
|
64324
64399
|
rejectCount: lineMeta[meta.lineId]?.rejectCount ?? 0,
|
|
64325
|
-
accepted: lineMeta[meta.lineId]?.accepted ?? false
|
|
64400
|
+
accepted: lineMeta[meta.lineId]?.accepted ?? false,
|
|
64401
|
+
// 号只读不发:这里是纯函数,发号在 linesOf 那一趟(store 是唯一发号点)
|
|
64402
|
+
ordinal: lineMeta[meta.lineId]?.ordinal ?? null
|
|
64326
64403
|
});
|
|
64327
64404
|
}
|
|
64328
64405
|
return out;
|
|
@@ -64333,7 +64410,15 @@ function buildTopicHandlers(deps) {
|
|
|
64333
64410
|
if (!t) throw new ClawdError(ERROR_CODES.INVALID_PARAM, `topic not found: ${topicId}`);
|
|
64334
64411
|
return t;
|
|
64335
64412
|
};
|
|
64336
|
-
const linesOf = (t) =>
|
|
64413
|
+
const linesOf = (t) => {
|
|
64414
|
+
const records = deps.dispatchStore.list({ sourceSessionId: t.masterSessionId });
|
|
64415
|
+
const inCreationOrder = records.slice().sort((a, b2) => a.createdAt < b2.createdAt ? -1 : a.createdAt > b2.createdAt ? 1 : 0);
|
|
64416
|
+
for (const r of inCreationOrder) {
|
|
64417
|
+
const lineId = r.meta?.lineId;
|
|
64418
|
+
if (typeof lineId === "string" && lineId) deps.topicStore.claimLineOrdinal(t.id, lineId);
|
|
64419
|
+
}
|
|
64420
|
+
return joinLines(records, t.lineMeta);
|
|
64421
|
+
};
|
|
64337
64422
|
return {
|
|
64338
64423
|
"topic:list": async (frame) => {
|
|
64339
64424
|
const { channelId } = TopicListArgsSchema.parse(frame);
|
|
@@ -66089,7 +66174,13 @@ async function startDaemon(config) {
|
|
|
66089
66174
|
genId: () => v4_default(),
|
|
66090
66175
|
store: dispatchStore,
|
|
66091
66176
|
now: () => Date.now(),
|
|
66092
|
-
onCompleted: (sid) => deliverPendingRef?.(sid)
|
|
66177
|
+
onCompleted: (sid) => deliverPendingRef?.(sid),
|
|
66178
|
+
// 建线即发号:dispatch 的 sourceSessionId 就是该话题的 Master session(1:1),
|
|
66179
|
+
// 反查得到话题后按建线先后领一个稳定的线号。派的不是话题线(反查不到话题)时 no-op。
|
|
66180
|
+
onLineClaimed: ({ sourceSessionId, lineId }) => {
|
|
66181
|
+
const topic = topicStore.getByMasterSession(sourceSessionId);
|
|
66182
|
+
if (topic) topicStore.claimLineOrdinal(topic.id, lineId);
|
|
66183
|
+
}
|
|
66093
66184
|
});
|
|
66094
66185
|
const here = typeof __dirname === "string" ? __dirname : import_node_path71.default.dirname((0, import_node_url4.fileURLToPath)(import_meta7.url));
|
|
66095
66186
|
const mcpConfigs = [];
|
|
@@ -21880,6 +21880,21 @@ var TopicActivityEntrySchema = external_exports.object({
|
|
|
21880
21880
|
var TopicLineMetaSchema = external_exports.object({
|
|
21881
21881
|
rejectCount: external_exports.number().int().min(0),
|
|
21882
21882
|
accepted: external_exports.boolean().default(false),
|
|
21883
|
+
/**
|
|
21884
|
+
* 该线在本话题内的**序号**,daemon 按建线先后顺序发,从 1 起。
|
|
21885
|
+
*
|
|
21886
|
+
* 存在的理由只有一个:老板说「第 2 条线」和 Master 说「线2」得指同一条。所以它必须
|
|
21887
|
+
* **稳定且不复用**——删掉第 2 条后新建的线拿 4 而不是 2,否则昨天说的号今天指向别的线,
|
|
21888
|
+
* 序号就没有价值了。发号点见 topic-store.claimLineOrdinal。
|
|
21889
|
+
*
|
|
21890
|
+
* 早先这个号是 UI 从 lineId 字符串里 parse 的(`line-<N>-<slug>`),等于把序号语义
|
|
21891
|
+
* 寄生在 Master 随手起的名字上:Master 用语义命名(`line-channel-fix`)就 parse 不出,
|
|
21892
|
+
* sidebar 整个不显示号。序号的产生端必须是 daemon。
|
|
21893
|
+
*
|
|
21894
|
+
* optional 而非 default:store 不按 schema parse(见 topic-store),存量 lineMeta
|
|
21895
|
+
* 里没有这个字段,读侧一律 `?? null`,回填由 `topic:get` 的发号 pass 幂等补上。
|
|
21896
|
+
*/
|
|
21897
|
+
ordinal: external_exports.number().int().min(1).optional(),
|
|
21883
21898
|
/**
|
|
21884
21899
|
* Master 在 watcher 判 fail 的情况下仍判合格的次数。
|
|
21885
21900
|
*
|
|
@@ -21904,6 +21919,19 @@ var TopicSchema = external_exports.object({
|
|
|
21904
21919
|
activity: external_exports.array(TopicActivityEntrySchema),
|
|
21905
21920
|
/** lineId -> 线级元数据 */
|
|
21906
21921
|
lineMeta: external_exports.record(TopicLineMetaSchema),
|
|
21922
|
+
/**
|
|
21923
|
+
* 线号水位:下一条线该拿的号。发一个加一,**只增不减**。
|
|
21924
|
+
*
|
|
21925
|
+
* 为什么是话题上的一个独立字段,而不是「现有 lineMeta 里的最大号 + 1」现算:现算的水位
|
|
21926
|
+
* 跟着现存线数走,删掉最大号那条线水位就退,下一条新线会**捡回那个号**。老板原话:
|
|
21927
|
+
* 「删了线,已经标记的线的序号不能变吧,要不然留档的记录不都坏了么」——号对不上只是难用,
|
|
21928
|
+
* 号能对上、却对到了另一条线(流水里「#3 判合格」后来指向一条新线)是把留档直接读坏。
|
|
21929
|
+
* 所以不变式有两条:**已发的号永不改**、**号永不复用**,后者必须与现存线数彻底脱钩。
|
|
21930
|
+
*
|
|
21931
|
+
* optional 而非 default:store 不按 schema parse(见 topic-store),存量话题没有这个
|
|
21932
|
+
* 字段,读盘时按「现有最大号 + 1」一次性归一(不能从 1 重开,否则现有的 #1 #2 会被复用)。
|
|
21933
|
+
*/
|
|
21934
|
+
nextLineOrdinal: external_exports.number().int().min(1).optional(),
|
|
21907
21935
|
state: TopicStateSchema,
|
|
21908
21936
|
createdAt: external_exports.string().min(1),
|
|
21909
21937
|
updatedAt: external_exports.string().min(1)
|
|
@@ -21918,7 +21946,14 @@ var TopicLineViewSchema = external_exports.object({
|
|
|
21918
21946
|
acceptance: external_exports.array(external_exports.string()),
|
|
21919
21947
|
rejectCount: external_exports.number().int().min(0),
|
|
21920
21948
|
/** 已被 Master 判定合格(`topic:accept`)。UI 的「合格」态靠它,不是猜的 */
|
|
21921
|
-
accepted: external_exports.boolean()
|
|
21949
|
+
accepted: external_exports.boolean(),
|
|
21950
|
+
/**
|
|
21951
|
+
* 线号(见 TopicLineMetaSchema.ordinal)。UI 直接渲染,**不再从 lineId 猜**。
|
|
21952
|
+
*
|
|
21953
|
+
* nullable 而非必填:joinLines 是纯函数,拿到的 lineMeta 里可能还没发过号(发号 pass
|
|
21954
|
+
* 在 handler 侧)。走 `topic:get` 出去的线一律已发号,null 只在纯函数被单独调用时出现。
|
|
21955
|
+
*/
|
|
21956
|
+
ordinal: external_exports.number().int().min(1).nullable()
|
|
21922
21957
|
});
|
|
21923
21958
|
var TopicListArgsSchema = external_exports.object({ channelId: external_exports.string().min(1) });
|
|
21924
21959
|
var TopicGetArgsSchema = external_exports.object({
|