@clawos-dev/clawd 0.2.224-beta.437.7f84075 → 0.2.225
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 +141 -5
- package/dist/share-md-viewer-error.html +1 -1
- package/dist/share-md-viewer.html +1 -1
- package/dist/share-ui/assets/guest-Bd7xlmHv.js +557 -0
- package/dist/share-ui/assets/guest-CZnc3fAe.css +32 -0
- package/dist/share-ui/guest.html +2 -2
- package/package.json +1 -1
- package/dist/share-ui/assets/guest-BER5fZM8.js +0 -557
- package/dist/share-ui/assets/guest-KbSE5PDA.css +0 -32
package/dist/cli.cjs
CHANGED
|
@@ -11379,6 +11379,45 @@ function hashDirToCwd(hash) {
|
|
|
11379
11379
|
const body = hash.startsWith("-") ? hash.slice(1) : hash;
|
|
11380
11380
|
return "/" + body.replace(/-/g, "/");
|
|
11381
11381
|
}
|
|
11382
|
+
function findTranscriptByToolSessionId(projectsRoot, toolSessionId) {
|
|
11383
|
+
let entries;
|
|
11384
|
+
try {
|
|
11385
|
+
entries = import_node_fs5.default.readdirSync(projectsRoot, { withFileTypes: true });
|
|
11386
|
+
} catch {
|
|
11387
|
+
return null;
|
|
11388
|
+
}
|
|
11389
|
+
let best = null;
|
|
11390
|
+
for (const ent of entries) {
|
|
11391
|
+
if (!ent.isDirectory()) continue;
|
|
11392
|
+
const candidate = import_node_path5.default.join(projectsRoot, ent.name, `${toolSessionId}.jsonl`);
|
|
11393
|
+
try {
|
|
11394
|
+
const st = import_node_fs5.default.statSync(candidate);
|
|
11395
|
+
if (!best || st.mtimeMs > best.mtime) best = { p: candidate, mtime: st.mtimeMs };
|
|
11396
|
+
} catch {
|
|
11397
|
+
}
|
|
11398
|
+
}
|
|
11399
|
+
return best?.p ?? null;
|
|
11400
|
+
}
|
|
11401
|
+
function deriveCwdFromTranscript(filePath) {
|
|
11402
|
+
const dirName = import_node_path5.default.basename(import_node_path5.default.dirname(filePath));
|
|
11403
|
+
let raw;
|
|
11404
|
+
try {
|
|
11405
|
+
raw = import_node_fs5.default.readFileSync(filePath, "utf8");
|
|
11406
|
+
} catch {
|
|
11407
|
+
return null;
|
|
11408
|
+
}
|
|
11409
|
+
let hit = null;
|
|
11410
|
+
for (const line of raw.split("\n")) {
|
|
11411
|
+
const t = line.trim();
|
|
11412
|
+
if (!t) continue;
|
|
11413
|
+
try {
|
|
11414
|
+
const o = JSON.parse(t);
|
|
11415
|
+
if (typeof o.cwd === "string" && cwdToHashDir(o.cwd) === dirName) hit = o.cwd;
|
|
11416
|
+
} catch {
|
|
11417
|
+
}
|
|
11418
|
+
}
|
|
11419
|
+
return hit;
|
|
11420
|
+
}
|
|
11382
11421
|
function safeStatMtime(p2) {
|
|
11383
11422
|
try {
|
|
11384
11423
|
return import_node_fs5.default.statSync(p2).mtimeMs;
|
|
@@ -42357,6 +42396,13 @@ function applyCommand(state, command, deps) {
|
|
|
42357
42396
|
}
|
|
42358
42397
|
return { state: next, effects };
|
|
42359
42398
|
}
|
|
42399
|
+
case "sync-cwd": {
|
|
42400
|
+
if (next.file.cwd === command.cwd) return { state: next, effects };
|
|
42401
|
+
next.file = { ...next.file, cwd: command.cwd, updatedAt: nowIso(deps) };
|
|
42402
|
+
effects.push({ kind: "persist-file", file: next.file });
|
|
42403
|
+
effects.push(sessionInfoFrame(next.file));
|
|
42404
|
+
return { state: next, effects };
|
|
42405
|
+
}
|
|
42360
42406
|
case "resume": {
|
|
42361
42407
|
const sameToolSession = next.file.toolSessionId === command.toolSessionId;
|
|
42362
42408
|
const nextFile = {
|
|
@@ -43955,6 +44001,23 @@ var SessionManager = class {
|
|
|
43955
44001
|
this.writeOwned(updated);
|
|
43956
44002
|
return { response: updated, broadcast: [] };
|
|
43957
44003
|
}
|
|
44004
|
+
/**
|
|
44005
|
+
* [T-17] observer 检测到 CC 挪走 transcript(cwd 中途变化)后的 cwd 校正入口。
|
|
44006
|
+
* 不进 withCollector:observer 回调没有 in-flight RPC,session:info 帧走
|
|
44007
|
+
* routeFromRunner 的异步 broadcast 路径。有 runner 走 reducer sync-cwd(无 kill,
|
|
44008
|
+
* 区别于 update 的 RUNTIME_PATCH_KEYS 重启语义);无 runner 直写 store。
|
|
44009
|
+
* 幂等:reducer 同值 noop;session 不存在静默返回(observer 生命周期与 store 解耦)。
|
|
44010
|
+
*/
|
|
44011
|
+
syncSessionCwd(sessionId, cwd) {
|
|
44012
|
+
const runner = this.runners.get(sessionId);
|
|
44013
|
+
if (runner) {
|
|
44014
|
+
runner.input({ kind: "command", command: { kind: "sync-cwd", cwd } });
|
|
44015
|
+
return;
|
|
44016
|
+
}
|
|
44017
|
+
const existing = this.findOwnedSession(sessionId);
|
|
44018
|
+
if (!existing || existing.cwd === cwd) return;
|
|
44019
|
+
this.writeOwned({ ...existing, cwd, updatedAt: nowIso2(this.deps) });
|
|
44020
|
+
}
|
|
43958
44021
|
/**
|
|
43959
44022
|
* 启动清扫:删除所有磁盘残留的 ephemeral(快速问答临时)session。
|
|
43960
44023
|
* 客户端崩溃 / 没关抽屉会留下永久不可见的孤儿(ephemeral 被 sidebar 过滤,用户自己也删不掉)。
|
|
@@ -49640,14 +49703,19 @@ var SessionObserver = class {
|
|
|
49640
49703
|
lastSize: size,
|
|
49641
49704
|
buf: "",
|
|
49642
49705
|
adapter: args.adapter,
|
|
49643
|
-
prevIsRejectSentinel: false
|
|
49706
|
+
prevIsRejectSentinel: false,
|
|
49707
|
+
toolSessionId: args.toolSessionId,
|
|
49708
|
+
sawFile: import_node_fs25.default.existsSync(filePath),
|
|
49709
|
+
lastRelocateScanMs: 0,
|
|
49710
|
+
pendingCwdDerive: false,
|
|
49711
|
+
lastDeriveMs: 0
|
|
49644
49712
|
};
|
|
49645
49713
|
try {
|
|
49646
49714
|
import_node_fs25.default.mkdirSync(import_node_path24.default.dirname(filePath), { recursive: true });
|
|
49647
49715
|
} catch {
|
|
49648
49716
|
}
|
|
49649
49717
|
w2.watcher = import_node_fs25.default.watch(import_node_path24.default.dirname(filePath), { persistent: false }, (_event, changedName) => {
|
|
49650
|
-
if (!changedName || !filePath.endsWith(changedName)) return;
|
|
49718
|
+
if (!changedName || !w2.filePath.endsWith(changedName)) return;
|
|
49651
49719
|
this.poll(w2);
|
|
49652
49720
|
});
|
|
49653
49721
|
w2.pollTimer = setInterval(() => this.poll(w2), 200);
|
|
@@ -49695,8 +49763,10 @@ var SessionObserver = class {
|
|
|
49695
49763
|
try {
|
|
49696
49764
|
size = import_node_fs25.default.statSync(w2.filePath).size;
|
|
49697
49765
|
} catch {
|
|
49766
|
+
if (w2.sawFile) this.maybeRelocate(w2);
|
|
49698
49767
|
return;
|
|
49699
49768
|
}
|
|
49769
|
+
w2.sawFile = true;
|
|
49700
49770
|
if (size < w2.lastSize) {
|
|
49701
49771
|
w2.lastSize = 0;
|
|
49702
49772
|
w2.buf = "";
|
|
@@ -49731,6 +49801,57 @@ var SessionObserver = class {
|
|
|
49731
49801
|
} finally {
|
|
49732
49802
|
import_node_fs25.default.closeSync(fd);
|
|
49733
49803
|
}
|
|
49804
|
+
if (w2.pendingCwdDerive) this.maybeDeriveCwd(w2);
|
|
49805
|
+
}
|
|
49806
|
+
// [T-17] 文件消失后的兜底重定位:按 tsid 全局扫描 → 切 watcher → lastSize/buf 保留接续读
|
|
49807
|
+
// (CC 是 move,内容前缀不变,不重复喂;异常变小走 poll 的截断重建分支,上游 uuid dedup 兜底)。
|
|
49808
|
+
// 检测点唯一(poll ENOENT),fs.watch rename 事件也 funnel 到 poll,天然幂等;scan 加 1s
|
|
49809
|
+
// rate-limit 防 ENOENT 持续期(如 cleanupPeriodDays 真删除)反复 readdir 空转。
|
|
49810
|
+
maybeRelocate(w2) {
|
|
49811
|
+
const now = Date.now();
|
|
49812
|
+
if (now - w2.lastRelocateScanMs < 1e3) return;
|
|
49813
|
+
w2.lastRelocateScanMs = now;
|
|
49814
|
+
const projectsRoot = import_node_path24.default.join(this.home, ".claude", "projects");
|
|
49815
|
+
const found = findTranscriptByToolSessionId(projectsRoot, w2.toolSessionId);
|
|
49816
|
+
if (!found || found === w2.filePath) return;
|
|
49817
|
+
try {
|
|
49818
|
+
w2.watcher?.close();
|
|
49819
|
+
} catch {
|
|
49820
|
+
}
|
|
49821
|
+
w2.filePath = found;
|
|
49822
|
+
try {
|
|
49823
|
+
w2.watcher = import_node_fs25.default.watch(import_node_path24.default.dirname(found), { persistent: false }, (_event, changedName) => {
|
|
49824
|
+
if (!changedName || !w2.filePath.endsWith(changedName)) return;
|
|
49825
|
+
this.poll(w2);
|
|
49826
|
+
});
|
|
49827
|
+
} catch {
|
|
49828
|
+
w2.watcher = null;
|
|
49829
|
+
}
|
|
49830
|
+
const cwd = deriveCwdFromTranscript(found);
|
|
49831
|
+
if (cwd) {
|
|
49832
|
+
this.applyDerivedCwd(w2, cwd);
|
|
49833
|
+
} else {
|
|
49834
|
+
w2.pendingCwdDerive = true;
|
|
49835
|
+
}
|
|
49836
|
+
this.opts.onJsonlRelocated?.(w2.sessionId, { filePath: found, cwd });
|
|
49837
|
+
this.poll(w2);
|
|
49838
|
+
}
|
|
49839
|
+
maybeDeriveCwd(w2) {
|
|
49840
|
+
const now = Date.now();
|
|
49841
|
+
if (now - w2.lastDeriveMs < 500) return;
|
|
49842
|
+
w2.lastDeriveMs = now;
|
|
49843
|
+
const cwd = deriveCwdFromTranscript(w2.filePath);
|
|
49844
|
+
if (!cwd) return;
|
|
49845
|
+
w2.pendingCwdDerive = false;
|
|
49846
|
+
this.applyDerivedCwd(w2, cwd);
|
|
49847
|
+
this.opts.onJsonlRelocated?.(w2.sessionId, { filePath: w2.filePath, cwd });
|
|
49848
|
+
}
|
|
49849
|
+
applyDerivedCwd(w2, cwd) {
|
|
49850
|
+
this.metaObserver?.start({
|
|
49851
|
+
sessionId: w2.sessionId,
|
|
49852
|
+
cwd,
|
|
49853
|
+
toolSessionId: w2.toolSessionId
|
|
49854
|
+
});
|
|
49734
49855
|
}
|
|
49735
49856
|
// 解析 JSONL 单行:仅当是主链 user 文本行(非 sidechain / 非 sub-agent / message.role='user'
|
|
49736
49857
|
// 且 content 含 text part)时,抽出 real uuid + 第一段 text + timestamp 上报。
|
|
@@ -54681,10 +54802,18 @@ function readJsonlEntries(file) {
|
|
|
54681
54802
|
}
|
|
54682
54803
|
function forkSession(input) {
|
|
54683
54804
|
const baseDir = input.baseDir ?? import_node_path47.default.join(import_node_os16.default.homedir(), ".claude");
|
|
54684
|
-
|
|
54685
|
-
|
|
54805
|
+
let projectDir = import_node_path47.default.join(baseDir, "projects", cwdToHashDir(input.cwd));
|
|
54806
|
+
let sourceFile = import_node_path47.default.join(projectDir, `${input.toolSessionId}.jsonl`);
|
|
54686
54807
|
if (!import_node_fs45.default.existsSync(sourceFile)) {
|
|
54687
|
-
|
|
54808
|
+
const found = findTranscriptByToolSessionId(
|
|
54809
|
+
import_node_path47.default.join(baseDir, "projects"),
|
|
54810
|
+
input.toolSessionId
|
|
54811
|
+
);
|
|
54812
|
+
if (!found) {
|
|
54813
|
+
throw new Error(`fork: source transcript not found: ${sourceFile}`);
|
|
54814
|
+
}
|
|
54815
|
+
sourceFile = found;
|
|
54816
|
+
projectDir = import_node_path47.default.dirname(found);
|
|
54688
54817
|
}
|
|
54689
54818
|
const entries = readJsonlEntries(sourceFile);
|
|
54690
54819
|
const mainEntries = entries.filter((e) => e.isSidechain !== true);
|
|
@@ -59686,6 +59815,13 @@ async function startDaemon(config) {
|
|
|
59686
59815
|
// daemon 内部转译,UI 看到的始终是 events 流里的 synth uuid(详见 manager 注释)
|
|
59687
59816
|
onUserMessageObserved: (sessionId, realUuid, text) => {
|
|
59688
59817
|
manager.recordRealUserUuid({ sessionId, realUuid, text });
|
|
59818
|
+
},
|
|
59819
|
+
// [T-17] CC 中途改 cwd 挪走 transcript:observer 重定位后校正 SessionFile.cwd
|
|
59820
|
+
// (persist + session:info,不 kill),fork / respawn / UI 缓存随之对齐。
|
|
59821
|
+
// cwd 可能两段式到达(挪走瞬间新 cwd 行未落盘 → 先 null 后补),回调幂等
|
|
59822
|
+
onJsonlRelocated: (sessionId, { filePath, cwd }) => {
|
|
59823
|
+
logger.info("observer jsonl relocated", { sessionId, filePath, cwd });
|
|
59824
|
+
if (cwd) manager.syncSessionCwd(sessionId, cwd);
|
|
59689
59825
|
}
|
|
59690
59826
|
});
|
|
59691
59827
|
manager.attachObserver(observer);
|