回收 411 MB(470 M → 58.8 M),全部经回收站,可恢复: - 待清理/(146.2 M,含 relay 分片 128 M 与 42 项过程目录) - tmp/(32.4 M,按接续棒命名的过程临时区) - .workbuddy/tmp/(39.5 M) - 4 份 workbuddy.db 冗余副本(101 M,09-23 事故的坏副本 / 抢救产物) - tmp/im16/gw/centrifugo 二进制(63.9 M,可重下)+ 缓存残留 入库范围:常驻规则(CODEBUDDY.md / README.md / state.py)、在途接续入口与 接续包、docs/、交付物/、交接单/、归档/、scripts/、.codebuddy/、 .workbuddy/memory/;共 398 件,其中 >60 KB 的 26 件全为文档。 排除(.gitignore):tmp/、待清理/、运行态日志与缓存、*.db 与 DB 备份整目录、 打包二进制(*.tar.gz / *.tgz)、记忆修复前备份。
89 lines
3.5 KiB
Python
89 lines
3.5 KiB
Python
#!/usr/bin/env python3
|
||
# 档案 24 后续:预置默认工作区(编辑器要求"必须选工作区"才能开会话 → 平台直接种 ws)
|
||
# 用法: python3 patch-seed-workspace.py /opt/dshs
|
||
import io
|
||
import os
|
||
import sys
|
||
|
||
root = sys.argv[1] if len(sys.argv) > 1 else '.'
|
||
p = os.path.join(root, 'src/supervisor/orchestrator.ts')
|
||
s = io.open(p, encoding='utf-8').read()
|
||
|
||
|
||
def sub(old, new, cnt=1):
|
||
global s
|
||
assert old in s, 'anchor not found:\n' + old[:200]
|
||
s = s.replace(old, new, cnt)
|
||
|
||
|
||
# 1) 补 fs 导入
|
||
sub(
|
||
"import { chmodSync, mkdirSync, writeFileSync } from 'node:fs'",
|
||
"import { chmodSync, chownSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs'",
|
||
)
|
||
|
||
# 2) 在 spawnInstance 里对 main 预置工作区
|
||
sub(
|
||
""" const map = role === 'main' ? this.mains : this.watchdogs
|
||
map.set(userId, instance)""",
|
||
""" const map = role === 'main' ? this.mains : this.watchdogs
|
||
map.set(userId, instance)
|
||
|
||
// 档案 24 后续:main 启动前预置默认工作区(编辑器要求"必须选择工作区"才能开始会话;
|
||
// 平台直接把用户 ws 种进 workspace 存储 → 用户开箱即用、且 UI 只显示短标题而非完整路径)。
|
||
if (isMain) await this.seedDefaultWorkspace(userId)""",
|
||
)
|
||
|
||
# 3) 新增 seedDefaultWorkspace 方法(放在 writePatch 之前)
|
||
sub(
|
||
""" /** Materialize the rendered patch so the dsh CLI can `--patch <file>` it.""",
|
||
""" /**
|
||
* 预置默认工作区(幂等,仅在工作区列表为空时写入):
|
||
* 把 `<userRoot>/ws` 以短标题「我的工作区」写进 `<home>/storages/workspace.json`,
|
||
* 使新用户/清空后无需手动选择工作区即可开始会话;已有工作区时**不覆盖**用户现状。
|
||
* 失败不阻断启动(只记日志)。
|
||
*/
|
||
private async seedDefaultWorkspace(userId: string): Promise<void> {
|
||
const root = userRoot(this.config.dataRoot, userId)
|
||
const dir = join(homeRoot(root), 'storages')
|
||
const file = join(dir, 'workspace.json')
|
||
try {
|
||
mkdirSync(dir, { recursive: true })
|
||
let existing: { global?: { workspaceIds?: unknown } } | undefined
|
||
try {
|
||
existing = JSON.parse(readFileSync(file, 'utf8')) as { global?: { workspaceIds?: unknown } }
|
||
} catch {
|
||
existing = undefined
|
||
}
|
||
const ids = existing?.global?.workspaceIds
|
||
if (Array.isArray(ids) && ids.length > 0) return // 已有工作区 → 尊重用户现状
|
||
const ws = workspaceRoot(root)
|
||
const id = randomUUID()
|
||
const now = new Date().toISOString()
|
||
const seed = {
|
||
unit: { name: 'workspace', version: 2 },
|
||
global: { initialized: true, workspaceIds: [id], archivedSessionIds: [] },
|
||
tables: {
|
||
workspaces: {
|
||
[id]: { path: ws, title: '我的工作区', sessionIds: [], createdAt: now, updatedAt: now },
|
||
},
|
||
},
|
||
}
|
||
writeFileSync(file, JSON.stringify(seed, null, 2) + '\\n')
|
||
const uid = await this.resolveUid(userId)
|
||
chownSync(file, uid, uid) // 实例以该 uid 运行,需可读写
|
||
chownSync(dir, uid, uid)
|
||
process.stderr.write(`[seed-workspace] ${userId} → ${ws}\\n`)
|
||
} catch (err) {
|
||
process.stderr.write(
|
||
`[seed-workspace] failed for ${userId}: ${err instanceof Error ? err.message : String(err)}\\n`,
|
||
)
|
||
}
|
||
}
|
||
|
||
/** Materialize the rendered patch so the dsh CLI can `--patch <file>` it.""",
|
||
)
|
||
|
||
io.open(p, 'w', encoding='utf-8', newline='').write(s)
|
||
print('patched: fs import + spawnInstance 调用 + seedDefaultWorkspace 方法')
|