@clawos-dev/clawd 0.2.373 → 0.2.375
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
CHANGED
|
@@ -11155,7 +11155,7 @@ var require_transport = __commonJS({
|
|
|
11155
11155
|
"use strict";
|
|
11156
11156
|
var { createRequire: createRequire2 } = require("module");
|
|
11157
11157
|
var getCallers = require_caller();
|
|
11158
|
-
var { join: join19, isAbsolute: isAbsolute4, sep:
|
|
11158
|
+
var { join: join19, isAbsolute: isAbsolute4, sep: sep4 } = require("path");
|
|
11159
11159
|
var sleep2 = require_atomic_sleep();
|
|
11160
11160
|
var onExit = require_on_exit_leak_free();
|
|
11161
11161
|
var ThreadStream = require_thread_stream();
|
|
@@ -11263,7 +11263,7 @@ var require_transport = __commonJS({
|
|
|
11263
11263
|
let fixTarget2;
|
|
11264
11264
|
for (const filePath of callers) {
|
|
11265
11265
|
try {
|
|
11266
|
-
const context = filePath === "node:repl" ? process.cwd() +
|
|
11266
|
+
const context = filePath === "node:repl" ? process.cwd() + sep4 : filePath;
|
|
11267
11267
|
fixTarget2 = createRequire2(context).resolve(origin);
|
|
11268
11268
|
break;
|
|
11269
11269
|
} catch (err) {
|
|
@@ -48218,13 +48218,6 @@ function readCodexProjects(opts) {
|
|
|
48218
48218
|
}
|
|
48219
48219
|
|
|
48220
48220
|
// src/projects/store.ts
|
|
48221
|
-
var DEFAULT_TMP_ROOTS = () => [
|
|
48222
|
-
"/tmp",
|
|
48223
|
-
"/private/tmp",
|
|
48224
|
-
"/var/folders",
|
|
48225
|
-
"/private/var/folders",
|
|
48226
|
-
path12.resolve(os5.tmpdir())
|
|
48227
|
-
];
|
|
48228
48221
|
var ProjectsStore = class {
|
|
48229
48222
|
constructor(opts) {
|
|
48230
48223
|
this.opts = opts;
|
|
@@ -48262,23 +48255,8 @@ var ProjectsStore = class {
|
|
|
48262
48255
|
const insideClawd = !(rel.startsWith("..") || path12.isAbsolute(rel));
|
|
48263
48256
|
if (insideClawd) return false;
|
|
48264
48257
|
if (abs === path12.resolve(os5.homedir()) || abs === path12.parse(abs).root) return false;
|
|
48265
|
-
for (const root of this.tmpRoots()) {
|
|
48266
|
-
if (abs === root || abs.startsWith(root.endsWith(path12.sep) ? root : root + path12.sep)) {
|
|
48267
|
-
return false;
|
|
48268
|
-
}
|
|
48269
|
-
}
|
|
48270
48258
|
return true;
|
|
48271
48259
|
}
|
|
48272
|
-
/** 层 2 的临时区根(缺省自适应,见构造器 opts.tmpRoots 注释) */
|
|
48273
|
-
tmpRoots() {
|
|
48274
|
-
if (this.opts.tmpRoots) return this.opts.tmpRoots;
|
|
48275
|
-
const defaults = DEFAULT_TMP_ROOTS();
|
|
48276
|
-
const clawd = path12.resolve(this.opts.clawdDir);
|
|
48277
|
-
const clawdItselfInTmp = defaults.some(
|
|
48278
|
-
(r) => clawd === r || clawd.startsWith(r + path12.sep)
|
|
48279
|
-
);
|
|
48280
|
-
return clawdItselfInTmp ? [] : defaults;
|
|
48281
|
-
}
|
|
48282
48260
|
list() {
|
|
48283
48261
|
return [...this.entries];
|
|
48284
48262
|
}
|
|
@@ -48302,6 +48280,7 @@ var ProjectsStore = class {
|
|
|
48302
48280
|
stateFile: this.opts.codexStateFile,
|
|
48303
48281
|
logger: this.opts.logger
|
|
48304
48282
|
})) {
|
|
48283
|
+
if (!c.createdAt) continue;
|
|
48305
48284
|
const abs = this.normalize(c.path);
|
|
48306
48285
|
if (!this.isProjectablePath(abs)) continue;
|
|
48307
48286
|
byPath.set(abs, {
|
|
@@ -59034,23 +59013,6 @@ function toMs(v2) {
|
|
|
59034
59013
|
const n = Number(v2 || 0);
|
|
59035
59014
|
return n > 1e11 ? Math.round(n) : Math.round(n * 1e3);
|
|
59036
59015
|
}
|
|
59037
|
-
function listFiles(dir, depth = 0, maxDepth = 8, out = []) {
|
|
59038
|
-
let entries;
|
|
59039
|
-
try {
|
|
59040
|
-
entries = import_node_fs46.default.readdirSync(dir, { withFileTypes: true });
|
|
59041
|
-
} catch {
|
|
59042
|
-
return out;
|
|
59043
|
-
}
|
|
59044
|
-
for (const e of entries) {
|
|
59045
|
-
const full = import_node_path51.default.join(dir, e.name);
|
|
59046
|
-
if (e.isDirectory()) {
|
|
59047
|
-
if (depth < maxDepth) listFiles(full, depth + 1, maxDepth, out);
|
|
59048
|
-
} else if (e.isFile()) {
|
|
59049
|
-
out.push(full);
|
|
59050
|
-
}
|
|
59051
|
-
}
|
|
59052
|
-
return out;
|
|
59053
|
-
}
|
|
59054
59016
|
async function* jsonLines(file) {
|
|
59055
59017
|
let raw;
|
|
59056
59018
|
try {
|
|
@@ -59108,6 +59070,7 @@ async function scanClaude(roots) {
|
|
|
59108
59070
|
continue;
|
|
59109
59071
|
}
|
|
59110
59072
|
let cwd = "";
|
|
59073
|
+
let entrypoint = "";
|
|
59111
59074
|
let title = "";
|
|
59112
59075
|
let firstUser = "";
|
|
59113
59076
|
let turns = 0;
|
|
@@ -59116,6 +59079,7 @@ async function scanClaude(roots) {
|
|
|
59116
59079
|
let hasMainLine = false;
|
|
59117
59080
|
for await (const rec4 of jsonLines(file)) {
|
|
59118
59081
|
if (!cwd && typeof rec4.cwd === "string") cwd = rec4.cwd;
|
|
59082
|
+
if (!entrypoint && typeof rec4.entrypoint === "string") entrypoint = rec4.entrypoint;
|
|
59119
59083
|
if (typeof rec4.timestamp === "string") {
|
|
59120
59084
|
const t = Date.parse(rec4.timestamp);
|
|
59121
59085
|
if (Number.isFinite(t)) {
|
|
@@ -59147,7 +59111,7 @@ async function scanClaude(roots) {
|
|
|
59147
59111
|
};
|
|
59148
59112
|
if (!hasMainLine) cand.skip = "subagent \u652F\u7EBF";
|
|
59149
59113
|
else if (!cwd) cand.skip = "\u65E0 cwd";
|
|
59150
|
-
else if (
|
|
59114
|
+
else if (entrypoint !== "cli" && entrypoint !== "claude-desktop") cand.skip = "\u975E\u7528\u6237\u5165\u53E3";
|
|
59151
59115
|
out.push(cand);
|
|
59152
59116
|
}
|
|
59153
59117
|
}
|
|
@@ -59168,7 +59132,7 @@ async function countCodexTurns(rolloutPath) {
|
|
|
59168
59132
|
return { turns, first };
|
|
59169
59133
|
}
|
|
59170
59134
|
function readCodexThreads(db) {
|
|
59171
|
-
const COLS = ["id", "cwd", "created_at", "updated_at", "name", "title", "preview", "first_user_message", "archived", "rollout_path"];
|
|
59135
|
+
const COLS = ["id", "cwd", "created_at", "updated_at", "name", "title", "preview", "first_user_message", "archived", "rollout_path", "thread_source"];
|
|
59172
59136
|
try {
|
|
59173
59137
|
const { DatabaseSync } = (0, import_node_module.createRequire)(import_meta4.url)("node:sqlite");
|
|
59174
59138
|
const conn = new DatabaseSync(db, { readOnly: true });
|
|
@@ -59176,7 +59140,7 @@ function readCodexThreads(db) {
|
|
|
59176
59140
|
const have = new Set(
|
|
59177
59141
|
conn.prepare("PRAGMA table_info(threads)").all().map((r) => r.name)
|
|
59178
59142
|
);
|
|
59179
|
-
if (!["id", "cwd", "updated_at"].every((c) => have.has(c))) return null;
|
|
59143
|
+
if (!["id", "cwd", "updated_at", "thread_source"].every((c) => have.has(c))) return null;
|
|
59180
59144
|
const sel = COLS.map((c) => have.has(c) ? c : `NULL AS ${c}`).join(", ");
|
|
59181
59145
|
return conn.prepare(`SELECT ${sel} FROM threads`).all();
|
|
59182
59146
|
} finally {
|
|
@@ -59190,7 +59154,7 @@ function readCodexThreads(db) {
|
|
|
59190
59154
|
const have = new Set(
|
|
59191
59155
|
info.stdout.split("\n").map((l) => l.split("|")[1]).filter(Boolean)
|
|
59192
59156
|
);
|
|
59193
|
-
if (!["id", "cwd", "updated_at"].every((c) => have.has(c))) return null;
|
|
59157
|
+
if (!["id", "cwd", "updated_at", "thread_source"].every((c) => have.has(c))) return null;
|
|
59194
59158
|
const sel = COLS.map((c) => have.has(c) ? c : `NULL AS ${c}`).join(", ");
|
|
59195
59159
|
const res = (0, import_node_child_process12.spawnSync)("sqlite3", ["-json", db, `SELECT ${sel} FROM threads;`], {
|
|
59196
59160
|
encoding: "utf8",
|
|
@@ -59218,58 +59182,22 @@ async function codexFromRows(rows) {
|
|
|
59218
59182
|
updatedMs,
|
|
59219
59183
|
skip: ""
|
|
59220
59184
|
};
|
|
59221
|
-
if (r.
|
|
59185
|
+
if (r.thread_source !== "user") cand.skip = "\u975E\u7528\u6237\u65B0\u5EFA";
|
|
59186
|
+
else if (r.archived) cand.skip = "\u5DF2\u5F52\u6863";
|
|
59222
59187
|
else if (!label) cand.skip = "\u7A7A\u4F1A\u8BDD";
|
|
59223
59188
|
out.push(cand);
|
|
59224
59189
|
}
|
|
59225
59190
|
return out;
|
|
59226
59191
|
}
|
|
59227
|
-
async function scanCodexRollouts(roots) {
|
|
59228
|
-
const out = [];
|
|
59229
|
-
for (const file of listFiles(import_node_path51.default.join(roots.codexDir, "sessions"))) {
|
|
59230
|
-
if (!file.endsWith(".jsonl")) continue;
|
|
59231
|
-
let st;
|
|
59232
|
-
try {
|
|
59233
|
-
st = import_node_fs46.default.statSync(file);
|
|
59234
|
-
} catch {
|
|
59235
|
-
continue;
|
|
59236
|
-
}
|
|
59237
|
-
let meta = null;
|
|
59238
|
-
for await (const rec4 of jsonLines(file)) {
|
|
59239
|
-
if (rec4.type === "session_meta") {
|
|
59240
|
-
meta = rec4.payload || {};
|
|
59241
|
-
break;
|
|
59242
|
-
}
|
|
59243
|
-
}
|
|
59244
|
-
const tid = meta && (meta.session_id || meta.id);
|
|
59245
|
-
if (!tid) continue;
|
|
59246
|
-
const { turns, first } = await countCodexTurns(file);
|
|
59247
|
-
const cand = {
|
|
59248
|
-
tool: "codex",
|
|
59249
|
-
toolSessionId: String(tid),
|
|
59250
|
-
cwd: String(meta?.cwd || ""),
|
|
59251
|
-
label: clipW(first, 56),
|
|
59252
|
-
turns,
|
|
59253
|
-
createdMs: st.mtimeMs,
|
|
59254
|
-
updatedMs: st.mtimeMs,
|
|
59255
|
-
skip: ""
|
|
59256
|
-
};
|
|
59257
|
-
if (!cand.cwd) cand.skip = "\u65E0 cwd";
|
|
59258
|
-
out.push(cand);
|
|
59259
|
-
}
|
|
59260
|
-
return out;
|
|
59261
|
-
}
|
|
59262
59192
|
async function scanCodex(roots) {
|
|
59263
59193
|
let dbs = [];
|
|
59264
59194
|
try {
|
|
59265
59195
|
dbs = import_node_fs46.default.readdirSync(roots.codexDir).filter((n) => /^state_.*\.sqlite$/.test(n)).sort().map((n) => import_node_path51.default.join(roots.codexDir, n));
|
|
59266
59196
|
} catch {
|
|
59267
59197
|
}
|
|
59268
|
-
if (dbs.length)
|
|
59269
|
-
|
|
59270
|
-
|
|
59271
|
-
}
|
|
59272
|
-
return scanCodexRollouts(roots);
|
|
59198
|
+
if (!dbs.length) return [];
|
|
59199
|
+
const rows = readCodexThreads(dbs[dbs.length - 1]);
|
|
59200
|
+
return rows ? codexFromRows(rows) : [];
|
|
59273
59201
|
}
|
|
59274
59202
|
async function scanExternalSessions(rootsIn) {
|
|
59275
59203
|
const roots = { ...defaultRoots(), ...rootsIn };
|
|
@@ -59300,14 +59228,19 @@ async function scanExternalSessions(rootsIn) {
|
|
|
59300
59228
|
var import_node_fs47 = __toESM(require("fs"), 1);
|
|
59301
59229
|
var import_node_path52 = __toESM(require("path"), 1);
|
|
59302
59230
|
var LEDGER_FILENAME = "session-import-ledger.json";
|
|
59303
|
-
function
|
|
59304
|
-
const file = import_node_path52.default.join(dataDir, LEDGER_FILENAME);
|
|
59305
|
-
let entries = [];
|
|
59231
|
+
function readImportLedger(dataDir) {
|
|
59306
59232
|
try {
|
|
59307
|
-
const parsed = JSON.parse(
|
|
59308
|
-
|
|
59233
|
+
const parsed = JSON.parse(
|
|
59234
|
+
import_node_fs47.default.readFileSync(import_node_path52.default.join(dataDir, LEDGER_FILENAME), "utf8")
|
|
59235
|
+
);
|
|
59236
|
+
return Array.isArray(parsed) ? parsed : [];
|
|
59309
59237
|
} catch {
|
|
59238
|
+
return [];
|
|
59310
59239
|
}
|
|
59240
|
+
}
|
|
59241
|
+
function appendImportLedger(dataDir, entry) {
|
|
59242
|
+
const file = import_node_path52.default.join(dataDir, LEDGER_FILENAME);
|
|
59243
|
+
const entries = readImportLedger(dataDir);
|
|
59311
59244
|
entries.push(entry);
|
|
59312
59245
|
import_node_fs47.default.writeFileSync(file, JSON.stringify(entries, null, 2), { encoding: "utf8", mode: 384 });
|
|
59313
59246
|
}
|
|
@@ -59416,6 +59349,9 @@ function buildSessionHandlers(deps) {
|
|
|
59416
59349
|
parseArgs2(SessionExternalScanArgs, frame, "session:externalScan args");
|
|
59417
59350
|
const owned = manager.list().response.sessions;
|
|
59418
59351
|
const linked = new Set(owned.map((f) => f.toolSessionId).filter(Boolean));
|
|
59352
|
+
if (deps.dataDir) {
|
|
59353
|
+
for (const e of readImportLedger(deps.dataDir)) linked.add(e.toolSessionId);
|
|
59354
|
+
}
|
|
59419
59355
|
const candidates = (await scanExternalSessions()).filter((c) => !linked.has(c.toolSessionId));
|
|
59420
59356
|
return { response: { candidates } };
|
|
59421
59357
|
};
|
|
@@ -59847,8 +59783,8 @@ function isGuestPathAllowed(grants, absPath, personaRoot, action = "read", userW
|
|
|
59847
59783
|
if (target === u || target.startsWith(u + usep)) return true;
|
|
59848
59784
|
}
|
|
59849
59785
|
const root = path65.resolve(personaRoot);
|
|
59850
|
-
const
|
|
59851
|
-
if (!target.startsWith(root +
|
|
59786
|
+
const sep4 = root.endsWith(path65.sep) ? "" : path65.sep;
|
|
59787
|
+
if (!target.startsWith(root + sep4)) return false;
|
|
59852
59788
|
const rel = path65.relative(root, target);
|
|
59853
59789
|
if (!rel || rel.startsWith("..")) return false;
|
|
59854
59790
|
const personaId2 = rel.split(path65.sep)[0];
|
|
@@ -59860,8 +59796,8 @@ function isGuestPathAllowed(grants, absPath, personaRoot, action = "read", userW
|
|
|
59860
59796
|
function personaIdFromPath(absPath, personaRoot) {
|
|
59861
59797
|
const root = path65.resolve(personaRoot);
|
|
59862
59798
|
const target = path65.resolve(absPath);
|
|
59863
|
-
const
|
|
59864
|
-
if (!target.startsWith(root +
|
|
59799
|
+
const sep4 = root.endsWith(path65.sep) ? "" : path65.sep;
|
|
59800
|
+
if (!target.startsWith(root + sep4)) return null;
|
|
59865
59801
|
const rel = path65.relative(root, target);
|
|
59866
59802
|
if (!rel || rel.startsWith("..")) return null;
|
|
59867
59803
|
const id = rel.split(path65.sep)[0];
|
|
@@ -59870,8 +59806,8 @@ function personaIdFromPath(absPath, personaRoot) {
|
|
|
59870
59806
|
function isPathWithin(dir, absPath) {
|
|
59871
59807
|
const d = path65.resolve(dir);
|
|
59872
59808
|
const t = path65.resolve(absPath);
|
|
59873
|
-
const
|
|
59874
|
-
return t === d || t.startsWith(d +
|
|
59809
|
+
const sep4 = d.endsWith(path65.sep) ? "" : path65.sep;
|
|
59810
|
+
return t === d || t.startsWith(d + sep4);
|
|
59875
59811
|
}
|
|
59876
59812
|
function isPathInGuestBoundary(personaRoot, personaId2, userWorkDir, absPath) {
|
|
59877
59813
|
if (userWorkDir && isPathWithin(userWorkDir, absPath)) return true;
|
|
@@ -61168,7 +61104,7 @@ function computeMethodAccess(args) {
|
|
|
61168
61104
|
}
|
|
61169
61105
|
|
|
61170
61106
|
// src/version.ts
|
|
61171
|
-
var version = "0.2.
|
|
61107
|
+
var version = "0.2.375".length > 0 ? "0.2.375" : "dev";
|
|
61172
61108
|
|
|
61173
61109
|
// src/cli-probe/probe.ts
|
|
61174
61110
|
var fs64 = __toESM(require("fs"), 1);
|
package/dist/persona-defaults/persona-clawd-butler/.claude/skills/clawd-session-import/SKILL.md
CHANGED
|
@@ -49,6 +49,10 @@ node .claude/skills/clawd-session-import/scripts/link-sessions.mjs --undo
|
|
|
49
49
|
node .claude/skills/clawd-session-import/scripts/link-sessions.mjs --undo --apply # 真删
|
|
50
50
|
```
|
|
51
51
|
|
|
52
|
+
台账里 session 已被手动删除的条目,`--undo` 只清账、不再调删除接口 —— 清掉后该会话
|
|
53
|
+
才能重新出现在「关联外部 session」的候选里(扫盘去重会读这本台账,见
|
|
54
|
+
`superpowers/specs/2026-08-19-external-scan-entrypoint-design.md` §4)。
|
|
55
|
+
|
|
52
56
|
## 原理
|
|
53
57
|
|
|
54
58
|
一条 clawd 会话的元数据里有 `cwd` + `toolSessionId` 两个字段,指向底层工具那条真实
|
|
@@ -485,9 +485,15 @@ async function doUndo(applyIt) {
|
|
|
485
485
|
const res = await rpc('session:list', { limit: 100000 })
|
|
486
486
|
const alive = new Set((res.sessions || []).map((s) => s.sessionId))
|
|
487
487
|
const todo = entries.filter((e) => alive.has(e.sessionId))
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
488
|
+
// 台账里 session 已经不在了(多半是用户直接在 clawd UI 里删的):没什么可删,只需
|
|
489
|
+
// 把账清掉。扫盘去重会读这本台账(spec 2026-08-19 §4),条目留着就等于该会话永久
|
|
490
|
+
// 无法重新导入,而 undo 的语义本就是「撤销我的导入记录」。
|
|
491
|
+
const stale = entries.filter((e) => !alive.has(e.sessionId))
|
|
492
|
+
console.log(`台账 ${entries.length} 条,其中 ${todo.length} 条还在` +
|
|
493
|
+
(stale.length ? `,${stale.length} 条已不存在(只清账)` : '') + '。' +
|
|
494
|
+
(applyIt ? '正在处理……' : '(预演;加 --apply 才真删)'))
|
|
495
|
+
for (const e of todo) console.log(` 删 ${e.sessionId} ${e.label || ''}`)
|
|
496
|
+
for (const e of stale) console.log(` 清账 ${e.sessionId} ${e.label || ''}`)
|
|
491
497
|
if (!applyIt) return
|
|
492
498
|
let removed = 0
|
|
493
499
|
const failed = new Set()
|
|
@@ -500,9 +506,13 @@ async function doUndo(applyIt) {
|
|
|
500
506
|
console.error(` 删 ${e.sessionId} 失败:${err.message}`)
|
|
501
507
|
}
|
|
502
508
|
}
|
|
503
|
-
|
|
509
|
+
// 清账范围 = 删成功的 + 本就不存在的;删失败的留在账上,下次 undo 还能重试
|
|
510
|
+
const doneIds = new Set([
|
|
511
|
+
...todo.map((t) => t.sessionId).filter((id) => !failed.has(id)),
|
|
512
|
+
...stale.map((s) => s.sessionId),
|
|
513
|
+
])
|
|
504
514
|
ledgerWrite(entries.filter((e) => !doneIds.has(e.sessionId)))
|
|
505
|
-
console.log(`已删除 ${removed} 条。原 Claude Code / Codex 的会话文件没有任何改动。`)
|
|
515
|
+
console.log(`已删除 ${removed} 条,清账 ${doneIds.size} 条。原 Claude Code / Codex 的会话文件没有任何改动。`)
|
|
506
516
|
}
|
|
507
517
|
|
|
508
518
|
// ---------------------------------------------------------------- 参数
|