@kanadego/dsh-heartbeat 1.9.1 → 1.9.3

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.
Files changed (43) hide show
  1. package/README.md +351 -374
  2. package/client.js +96 -20
  3. package/config/policy.json +4 -3
  4. package/cordis.patch.yml +18 -39
  5. package/dist/{chunk-BQCXYE7N.js → chunk-3MDBU6WY.js} +2 -2
  6. package/dist/{chunk-OYVNWB5G.js → chunk-CUOSICYJ.js} +2 -2
  7. package/dist/{chunk-KOOQOMQY.js → chunk-JDH2LDFS.js} +2 -2
  8. package/dist/chunk-K5Y6JP2B.js +399 -0
  9. package/dist/chunk-K5Y6JP2B.js.map +1 -0
  10. package/dist/{chunk-QOQ7EPZZ.js → chunk-KB5SMG3F.js} +3 -3
  11. package/dist/{chunk-HT57FOEF.js → chunk-TRO4E6WG.js} +164 -35
  12. package/dist/chunk-TRO4E6WG.js.map +1 -0
  13. package/dist/{chunk-WRJCINZ7.js → chunk-WLZSABBH.js} +20 -6
  14. package/dist/chunk-WLZSABBH.js.map +1 -0
  15. package/dist/{chunk-2NB4QILF.js → chunk-XFNCTOW7.js} +2 -2
  16. package/dist/{chunk-ZLV4NMFX.js → chunk-XYYEJK3W.js} +4 -1
  17. package/dist/chunk-XYYEJK3W.js.map +1 -0
  18. package/dist/cli/index.js +10 -10
  19. package/dist/cli/index.js.map +1 -1
  20. package/dist/{inbox-JLT5G7TL.js → inbox-P26DDMWC.js} +3 -3
  21. package/dist/index.d.ts +35 -0
  22. package/dist/index.js +137 -26
  23. package/dist/index.js.map +1 -1
  24. package/dist/{migrate-WDVFHUP7.js → migrate-D4VKAKYT.js} +3 -3
  25. package/dist/{orchestrator-2ZLU7RGE.js → orchestrator-ZPRGVDCB.js} +16 -10
  26. package/dist/{pool-B34NTH6D.js → pool-UTXQJJ5C.js} +3 -3
  27. package/dist/{snapshot-JQDJ346Z.js → snapshot-K5VHETTK.js} +4 -4
  28. package/package.json +83 -83
  29. package/dist/chunk-7TW6DD6Q.js +0 -208
  30. package/dist/chunk-7TW6DD6Q.js.map +0 -1
  31. package/dist/chunk-HT57FOEF.js.map +0 -1
  32. package/dist/chunk-WRJCINZ7.js.map +0 -1
  33. package/dist/chunk-ZLV4NMFX.js.map +0 -1
  34. /package/dist/{chunk-BQCXYE7N.js.map → chunk-3MDBU6WY.js.map} +0 -0
  35. /package/dist/{chunk-OYVNWB5G.js.map → chunk-CUOSICYJ.js.map} +0 -0
  36. /package/dist/{chunk-KOOQOMQY.js.map → chunk-JDH2LDFS.js.map} +0 -0
  37. /package/dist/{chunk-QOQ7EPZZ.js.map → chunk-KB5SMG3F.js.map} +0 -0
  38. /package/dist/{chunk-2NB4QILF.js.map → chunk-XFNCTOW7.js.map} +0 -0
  39. /package/dist/{inbox-JLT5G7TL.js.map → inbox-P26DDMWC.js.map} +0 -0
  40. /package/dist/{migrate-WDVFHUP7.js.map → migrate-D4VKAKYT.js.map} +0 -0
  41. /package/dist/{orchestrator-2ZLU7RGE.js.map → orchestrator-ZPRGVDCB.js.map} +0 -0
  42. /package/dist/{pool-B34NTH6D.js.map → pool-UTXQJJ5C.js.map} +0 -0
  43. /package/dist/{snapshot-JQDJ346Z.js.map → snapshot-K5VHETTK.js.map} +0 -0
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/cli/index.ts","../../src/vault/burn-list.ts"],"sourcesContent":["// Operational CLI (design doc §14). Commands grow per module.\n// Run: node dist/cli/index.js <command> [args] (or via tsx in dev)\n//\n// H-42: `main` used to be a 530-line function with a switch holding every\n// verb's body. The verbs are module-level functions now (see CliCtx below) and\n// `main` only builds the shared context and dispatches — one place to add a\n// command, and each verb is readable on its own.\n\nimport { spawn } from 'node:child_process';\nimport fs from 'node:fs';\nimport os from 'node:os';\nimport path from 'node:path';\nimport { initWorkspace } from '../core/paths.js';\nimport type { WorkspacePaths } from '../core/paths.js';\nimport { createPathGuard } from '../core/path-guard.js';\nimport type { PathGuard } from '../core/path-guard.js';\nimport { appendAuditLine, pruneAuditFile } from '../core/audit-log.js';\nimport { atomicWriteFileSync } from '../core/atomic-fs.js';\nimport { loadPolicy } from '../config/load.js';\nimport type { Policy } from '../config/schema.js';\nimport {\n addSeed,\n archiveSeedById,\n gcPool,\n loadPool,\n activeSeeds,\n archivedSeeds,\n seedsFilePath,\n surfaceSeed,\n} from '../seeds/pool.js';\nimport type { SeedSource, SeedTag } from '../seeds/types.js';\nimport {\n appendEntry,\n ledgerFilePath,\n markDone,\n readLedger,\n scanPending,\n} from '../ledger/ledger.js';\nimport {\n adviseWander,\n browseStatus,\n completeWander,\n loadInterests,\n} from '../browse/browse.js';\nimport { ensureRegistered, sendNewMessageHint } from '../notify/notify.js';\nimport {\n loadProfile,\n profileFilePath,\n verifyProfile,\n rebuildProfile,\n} from '../profile/store.js';\nimport { planBurn, executeBurn } from '../vault/burn-list.js';\nimport {\n collectMigrationEntries,\n encryptContainer,\n decryptContainer,\n applyMigrationEntries,\n} from '../vault/migrate.js';\nimport { listWeeklyReports, readWeeklyReport, weeklyDirPath } from '../weekly/report.js';\nimport { writeText } from '../vault/vault.js';\nimport {\n BUNDLED_PRESET_ID,\n conventionalUserPresetRoot,\n describeInstall,\n installBundledPreset,\n presetStatus,\n} from '../core/preset-install.js';\n\nfunction usage(): string {\n return [\n 'usage: heartbeat <command> [args]',\n '',\n 'commands:',\n ' status workspace paths + policy summary',\n ' seeds add <text> [--tag t] [--source s] [--topic x] [--confidence n]',\n ' seeds list [--archived] list active (or archived) seeds',\n ' seeds surface <id> count a surfacing (rule 1 accounting)',\n ' seeds archive <id> deliberate retirement (completed)',\n ' seeds gc run deterministic eviction rules 1-3',\n ' seeds stats pool status JSON',\n ' ledger add <text> register an open item',\n ' ledger list [--pending] list entries',\n ' ledger done <id|substring> mark an entry done',\n ' ledger open open ledger.md in the default editor',\n ' logs cleanup [--dry-run] apply log retention now',\n ' browse status browse state summary (wander)',\n ' browse dry wander adjudication with forced noon window',\n ' browse done <focus> CODE-side registration after a wander visit',\n ' bind list list session bindings (D13)',\n ' bind add <sessionId> [--observe] bind a session (deliver by default)',\n ' bind remove <sessionId> unbind a session',\n ' sessions list enumerate persisted sessions (ids)',\n ' notify check|register|send toast channel (D12: hint only, no body)',\n ' profile list [--all] current valid (or all incl. expired) entries',\n ' profile export decrypted Markdown export to data/exports/',\n ' profile verify journal replay vs disk (report only)',\n ' profile rebuild [--check] rebuild materialized view from journal',\n ' profile snapshot [--force] fold the journal into a snapshot + archive shard',\n ' profile wipe wipe profile data (asks --yes)',\n ' weekly list list generated weekly reports',\n ' weekly show [file] print a report (default: newest)',\n ' migrate export [file] pack memory files into a passphrase container (passphrase: 2 stdin lines)',\n ' migrate import <file> restore a container into this workspace (passphrase: 1 stdin line)',\n ' burn [--yes] [--all] shred runtime data (settings kept unless --all)',\n ' preset status bundled agent preset: target dir + installed?',\n ' preset install [--force] install the bundled preset (never overwrites unless --force)',\n ].join('\\n');\n}\n\nfunction readStdinText(): string {\n try {\n return fs.readFileSync(0, 'utf8').trim();\n } catch {\n return '';\n }\n}\n\nfunction flag(argv: string[], name: string): string | undefined {\n const i = argv.indexOf(name);\n return i > -1 ? argv[i + 1] : undefined;\n}\n\n/** H-42: the seed flags used to be written `flag(rest, '--tag') as never` — the\n * escape hatch threw the type away, so a typo landed in the seed record\n * unchecked. Validate against the known sets instead (the `satisfies` clauses\n * keep these lists in step with the types). */\nconst SEED_TAGS = ['news', 'fandom', 'scene', 'promise'] as const satisfies readonly SeedTag[];\nconst SEED_SOURCES = ['chat', 'screen', 'browse', 'hand', 'profile'] as const satisfies readonly SeedSource[];\n\nfunction flagOneOf<T extends string>(argv: string[], name: string, allowed: readonly T[]): T | undefined {\n const v = flag(argv, name);\n if (v === undefined) return undefined;\n return (allowed as readonly string[]).includes(v) ? (v as T) : undefined;\n}\n\n/** Read N lines from stdin (passphrase prompts for migrate). */\nasync function readLines(prompts: string[]): Promise<string[]> {\n const readline = await import('node:readline/promises');\n const it = readline.createInterface({ input: process.stdin });\n const out: string[] = [];\n for (const p of prompts) out.push((await it.question(p)).trim());\n it.close();\n return out;\n}\n\n/** Everything a verb needs. Built once in {@link main}; `sub`/`rest` are the\n * positional split of argv, `argv` stays available for top-level flags. */\ninterface CliCtx {\n paths: WorkspacePaths;\n guard: PathGuard;\n policy: Policy;\n sub: string | undefined;\n rest: string[];\n argv: string[];\n seedsFile: string;\n ledgerFile: string;\n decisionLog: string;\n seedAudit: (entry: Record<string, unknown>) => void;\n}\n\ntype Verb = (c: CliCtx) => Promise<number>;\n\nasync function verbStatus(c: CliCtx): Promise<number> {\n const { paths, policy } = c;\n console.log(JSON.stringify({\n dataDir: paths.dataDir,\n heartbeatIntervalMin: policy.heartbeat.intervalMin,\n maxDailySend: policy.gate.maxDailySend,\n seedsMaxActive: policy.seeds.maxActive,\n psyEnabled: policy.profile.psyEnabled,\n }, null, 2));\n return 0;\n}\n\nasync function verbSeeds(c: CliCtx): Promise<number> {\n const { guard, policy, sub, rest, seedsFile, seedAudit } = c;\n switch (sub) {\n case 'add': {\n let text = rest[0]?.trim() ?? '';\n if (text === '-') text = readStdinText();\n if (!text) {\n console.error('usage: seeds add <text|-> [--tag t] [--source s] [--topic x] [--confidence n]');\n return 1;\n }\n const result = addSeed(guard, seedsFile, policy, {\n text,\n tag: flagOneOf(rest, '--tag', SEED_TAGS),\n source: flagOneOf(rest, '--source', SEED_SOURCES),\n topic: flag(rest, '--topic'),\n confidence: flag(rest, '--confidence') ? Number(flag(rest, '--confidence')) : undefined,\n }, Date.now(), seedAudit);\n if (result.kind === 'duplicate') {\n console.log(`DUPLICATE: active seed ${result.seed.id} has the same text`);\n return 0;\n }\n console.log(`${result.kind.toUpperCase()} ${result.seed.id}` +\n ` (${activeSeeds(loadPool(guard, seedsFile)).length}/${policy.seeds.maxActive})` +\n (result.evicted ? ` [evicted ${result.evicted.id}: ${result.evicted.retireReason}]` : ''));\n return 0;\n }\n case 'list': {\n const db = loadPool(guard, seedsFile);\n const items = rest.includes('--archived') ? archivedSeeds(db) : activeSeeds(db);\n for (const s of items) {\n const ageDays = Math.floor((Date.now() - Date.parse(s.bornAt)) / 86_400_000);\n console.log(`${s.id} [${s.tag}/${s.source}] d${ageDays} used:${s.used}` +\n `${s.protected ? ' *' : ''} ${s.text.slice(0, 60)}`);\n }\n if (items.length === 0) console.log('(empty)');\n return 0;\n }\n case 'surface': {\n const s = surfaceSeed(guard, seedsFile, policy, rest[0] ?? '', Date.now(), seedAudit);\n if (!s) {\n console.log('NOT_FOUND');\n return 1;\n }\n console.log(`SURFACED ${s.id} used:${s.used}${s.status === 'archived' ? ' -> archived (consumed)' : ''}`);\n return 0;\n }\n case 'archive': {\n const s = archiveSeedById(guard, seedsFile, rest[0] ?? '', 'completed', Date.now(), seedAudit);\n if (!s) {\n console.log('NOT_FOUND');\n return 1;\n }\n console.log(`ARCHIVED ${s.id}`);\n return 0;\n }\n case 'gc': {\n const report = gcPool(guard, seedsFile, policy, Date.now(), seedAudit);\n console.log(`GC consumed:${report.consumed} expired:${report.expired} cold_bench:${report.coldBench}` +\n ` archive_trimmed:${report.archiveTrimmed} -> active ${report.activeAfter}/${policy.seeds.maxActive}` +\n ` archive ${archivedSeeds(loadPool(guard, seedsFile)).length}/${policy.seeds.archiveCap}`);\n return 0;\n }\n case 'stats': {\n const db = loadPool(guard, seedsFile);\n console.log(JSON.stringify({\n active: activeSeeds(db).length,\n archived: archivedSeeds(db).length,\n cap: policy.seeds.maxActive,\n seq: db.seq,\n }, null, 2));\n return 0;\n }\n default:\n console.error(`unknown seeds subcommand: ${sub}`);\n return 1;\n }\n}\n\nasync function verbLedger(c: CliCtx): Promise<number> {\n const { guard, sub, rest, ledgerFile } = c;\n switch (sub) {\n case 'add': {\n let text = rest.join(' ').trim();\n if (text === '-') text = readStdinText();\n if (!text) {\n console.error('usage: ledger add <text|->');\n return 1;\n }\n const e = appendEntry(guard, ledgerFile, text);\n console.log(`OPEN #${e.id} ${e.text.slice(0, 60)}`);\n return 0;\n }\n case 'list': {\n const { entries } = readLedger(guard, ledgerFile);\n const items = rest.includes('--pending') ? scanPending(guard, ledgerFile) : entries;\n for (const e of items) console.log(`${e.status === 'open' ? ' ' : 'x'} #${e.id} ${e.date} ${e.text.slice(0, 60)}`);\n if (items.length === 0) console.log('(empty)');\n return 0;\n }\n case 'done': {\n const key = rest.join(' ').trim();\n if (!key) {\n console.error('usage: ledger done <id|substring>');\n return 1;\n }\n const e = markDone(guard, ledgerFile, key);\n if (!e) {\n console.log('NOT_FOUND');\n return 1;\n }\n console.log(`DONE #${e.id}`);\n return 0;\n }\n case 'open': {\n const f = ledgerFile;\n if (!fs.existsSync(f)) {\n console.log(`(ledger will be created at ${f})`);\n }\n spawn('cmd', ['/c', 'start', '', f], { detached: true, stdio: 'ignore' }).unref();\n console.log(`opened ${f}`);\n return 0;\n }\n default:\n console.error(`unknown ledger subcommand: ${sub}`);\n return 1;\n }\n}\n\nasync function verbWeekly(c: CliCtx): Promise<number> {\n const { guard, paths, sub, rest } = c;\n const reports = listWeeklyReports(guard, paths.dataDir);\n if (sub === 'list' || sub === undefined) {\n if (reports.length === 0) console.log('(no reports yet — heartbeat generates one every 7 days)');\n for (const r of reports) console.log(`${r.file} ${r.start.slice(0, 10)} ~ ${r.end.slice(0, 10)} [${r.source}]`);\n return 0;\n }\n if (sub === 'show') {\n const file = rest[0] ?? reports[0]?.file;\n if (!file) {\n console.log('(no reports yet)');\n return 1;\n }\n const rep = readWeeklyReport(guard, paths.dataDir, file);\n if (!rep) {\n console.error(`no such report: ${file} (see: weekly list; files live in ${weeklyDirPath(paths.dataDir)})`);\n return 1;\n }\n console.log(`# ${rep.start.slice(0, 10)} ~ ${rep.end.slice(0, 10)} [${rep.source}]`);\n console.log(rep.text);\n return 0;\n }\n console.error(`unknown weekly subcommand: ${sub}`);\n return 1;\n}\n\nasync function verbLogs(c: CliCtx): Promise<number> {\n const { paths, policy, sub, rest, decisionLog } = c;\n if (sub !== 'cleanup') {\n console.error('usage: logs cleanup [--dry-run]');\n return 1;\n }\n const dry = rest.includes('--dry-run');\n const envPulse = path.join(paths.logsDir, 'envpulse.jsonl');\n const cut1 = policy.retention.envPulseHours * 3600_000;\n const cut2 = policy.retention.decisionLogDays * 86_400_000;\n if (dry) {\n console.log(`(dry-run) would prune ${envPulse} to ${policy.retention.envPulseHours}h` +\n ` and ${decisionLog} to ${policy.retention.decisionLogDays}d`);\n return 0;\n }\n const a = pruneAuditFile(envPulse, cut1);\n const b = pruneAuditFile(decisionLog, cut2);\n appendAuditLine(decisionLog, { event: 'retention', pruned_envpulse: a, pruned_decision: b });\n console.log(`PRUNED envpulse:${a} decision:${b}`);\n return 0;\n}\n\nasync function verbBrowse(c: CliCtx): Promise<number> {\n const { guard, paths, policy, sub, rest } = c;\n switch (sub) {\n case 'status': {\n const st = browseStatus(guard, paths);\n const interests = loadInterests(paths);\n console.log(JSON.stringify({\n lastWanderAt: st.wander.last_wander_at ? new Date(st.wander.last_wander_at).toISOString() : null,\n focusCount: st.wander.focusCount,\n interestCount: interests.interests?.length ?? 0,\n }, null, 2));\n return 0;\n }\n case 'dry': {\n const forced = new Date();\n forced.setHours(12, 0, 0, 0);\n const advice = adviseWander(guard, paths, policy, forced);\n console.log(JSON.stringify(advice, null, 2));\n return 0;\n }\n case 'done': {\n const focus = rest.join(' ').trim();\n if (!focus) {\n console.error('usage: browse done <focus>');\n return 1;\n }\n const r = completeWander(guard, paths, focus);\n console.log(JSON.stringify(r));\n return 0;\n }\n default:\n console.error(`unknown browse subcommand: ${sub}`);\n return 1;\n }\n}\n\nasync function verbNotify(c: CliCtx): Promise<number> {\n const { paths, sub } = c;\n switch (sub) {\n case 'check':\n console.log(await ensureRegistered(paths) ? 'REGISTERED: yes' : 'REGISTERED: no');\n return 0;\n case 'register':\n await ensureRegistered(paths);\n console.log('register attempted');\n return 0;\n case 'send':\n console.log(await sendNewMessageHint(paths) ? 'SENT' : 'FAILED');\n return 0;\n default:\n console.error('usage: notify check|register|send');\n return 1;\n }\n}\n\nasync function verbProfile(c: CliCtx): Promise<number> {\n const { guard, paths, sub, rest } = c;\n const doc = loadProfile(guard, profileFilePath(paths.dataDir));\n const all = rest.includes('--all');\n switch (sub) {\n case 'list': {\n let n = 0;\n for (const p of ['interest', 'projects', 'comm', 'psy'] as const) {\n for (const e of doc.partitions[p]!.entries) {\n if (!all && e.validTo !== null) continue;\n n += 1;\n console.log(`${e.id} [${e.partition}/${e.topic}/${e.subTopic}] ${e.temporal}` +\n ` conf=${e.confidence.toFixed(2)}${e.lowActivity ? ' 久未验证' : ''}${e.validTo ? ' [失效]' : ''}: ${e.content.slice(0, 60)}`);\n }\n }\n if (n === 0) console.log('(empty)');\n return 0;\n }\n case 'export': {\n const lines = [`# 画像导出 ${new Date().toISOString()}`, ''];\n for (const p of ['interest', 'projects', 'comm', 'psy'] as const) {\n lines.push(`## ${p}`);\n for (const e of doc.partitions[p]!.entries) {\n if (e.validTo !== null) continue;\n lines.push(`- [${e.topic}/${e.subTopic}] ${e.content} (conf ${e.confidence.toFixed(2)}, ${e.temporal})`);\n }\n }\n const out = path.join(paths.exportsDir, `profile-export-${Date.now()}.md`);\n writeText(guard, out, lines.join('\\n') + '\\n');\n console.log(`EXPORTED: ${out}`);\n return 0;\n }\n case 'verify': {\n const r = verifyProfile(guard, paths.dataDir);\n console.log(JSON.stringify(r, null, 2));\n return r.ok ? 0 : 1;\n }\n case 'rebuild': {\n const r = rebuildProfile(guard, paths.dataDir, { check: rest.includes('--check') });\n console.log(JSON.stringify(r, null, 2));\n return r.ok ? 0 : 1;\n }\n case 'wipe': {\n if (!rest.includes('--yes')) {\n console.log('REFUSED: add --yes to wipe profile data (profile.json/inbox/journal)');\n return 1;\n }\n for (const f of ['profile.json', 'profile_inbox.jsonl', 'profile_journal.jsonl']) {\n const abs = guard.assert(path.join(paths.dataDir, f));\n if (fs.existsSync(abs)) fs.rmSync(abs, { force: true });\n }\n console.log('WIPED (settings preserved; use burn for full shredding)');\n return 0;\n }\n case 'snapshot': {\n const { snapshotDue, snapshotProfile, SNAPSHOT_THRESHOLD } = await import('../profile/snapshot.js');\n const { needed, lines } = snapshotDue(guard, paths.dataDir);\n console.log(`journal ${lines} 条(阈值 ${SNAPSHOT_THRESHOLD})`);\n if (!needed && !rest.includes('--force')) {\n console.log('未到阈值,未执行(加 --force 强制折叠)。');\n return 0;\n }\n const report = snapshotProfile(guard, paths.dataDir);\n if (!report.ok) {\n console.log(`未执行:${report.reason}`);\n return 0;\n }\n console.log(`已折叠 ${report.folded} 条 → 快照(baseline ${report.baselineTs}),归档 ${report.archiveFile},live journal 已清空。`);\n console.log('verify/rebuild 自动从快照基点重放,无需额外操作。');\n return 0;\n }\n default:\n console.error(`unknown profile subcommand: ${sub}`);\n return 1;\n }\n}\n\nasync function verbBurn(c: CliCtx): Promise<number> {\n const { guard, paths, rest } = c;\n const yes = rest.includes('--yes');\n const all = rest.includes('--all');\n const plan = planBurn(guard, paths, all);\n console.log('预演(不会执行):');\n for (const p of plan) console.log(` [${p.exists ? '存在' : '无 '}] ${p.target.file ?? p.target.dir} ${p.target.note}`);\n if (!yes) {\n console.log('\\n此操作会让心跳 agent 失忆。确认执行请加 --yes(' + (all ? '含 --all 连用户设定' : '用户设定保留') + ')');\n return 0;\n }\n const result = executeBurn(guard, paths, { all });\n console.log(`BURNED: ${result.burned.length} 项;MISSING: ${result.missing.length} 项`);\n return 0;\n}\n\nasync function verbMigrate(c: CliCtx): Promise<number> {\n const { guard, paths, sub, rest } = c;\n if (sub === 'export') {\n const defaultOut = path.join(paths.exportsDir, `heartbeat-memory-${new Date().toISOString().slice(0, 10)}.hbmig`);\n const outfile = rest[0] ?? defaultOut;\n let outCanon: string;\n try {\n outCanon = guard.assert(outfile);\n } catch {\n console.error(`导出文件必须落在插件 data/ 目录内(路径守卫拒绝):${outfile}\\n默认位置:${defaultOut}`);\n return 1;\n }\n const [pw1, pw2] = await readLines(['设置口令(用于加密迁移包): ', '再输入一次确认: ']);\n if (!pw1 || pw1 !== pw2) {\n console.error('两次输入不一致或为空,已取消。');\n return 1;\n }\n const { entries, progress } = collectMigrationEntries(guard, paths);\n if (entries.length === 0) {\n console.log('没有可打包的记忆文件(data/ 是空的)。');\n return 1;\n }\n fs.mkdirSync(path.dirname(outCanon), { recursive: true });\n atomicWriteFileSync(outCanon, encryptContainer(entries, pw1));\n console.log(`已打包 ${entries.length} 个文件 → ${outCanon}`);\n console.log(` 打包:${progress.packed.join(', ')}`);\n if (progress.missing.length > 0) console.log(` 跳过(不存在):${progress.missing.join(', ')}`);\n console.log('容器是口令加密的,可安全拷贝到新机器;DPAPI 会在导入时用新机器重新加密。');\n return 0;\n }\n if (sub === 'import') {\n const infile = rest[0];\n if (!infile) {\n console.error('usage: migrate import <container-file>');\n return 1;\n }\n const [pw] = await readLines(['输入迁移包口令: ']);\n let text: string;\n try {\n text = fs.readFileSync(infile, 'utf8');\n } catch {\n console.error(`读不到迁移包:${infile}`);\n return 1;\n }\n let files;\n try {\n files = decryptContainer(text, pw ?? '');\n } catch (e) {\n console.error(String(e instanceof Error ? e.message : e));\n return 1;\n }\n const result = applyMigrationEntries(guard, paths, files.files);\n console.log(`恢复 ${result.restored.length} 个文件;备份 ${result.backedUp.length} 个被覆盖文件;跳过 ${result.skipped.length} 个。`);\n for (const r of result.restored) console.log(` 恢复: ${r}`);\n for (const b of result.backedUp) console.log(` 备份: ${b}.bak-migrate-*`);\n if (result.skipped.length > 0) console.log(` 跳过: ${result.skipped.join(', ')}`);\n if (result.error) console.log(` 失败并已回滚:${result.error}`);\n console.log('重启 DSH 后生效。');\n return result.error ? 1 : 0;\n }\n console.error(`unknown migrate subcommand: ${sub}`);\n return 1;\n}\n\nasync function verbSessions(c: CliCtx): Promise<number> {\n const { guard, paths } = c;\n // Read-only enumeration of the host's persisted sessions (ids from the\n // on-disk store; titles live server-side and are not listed here).\n const root = path.join(os.homedir(), '.dsh', 'sessions');\n let found = 0;\n if (fs.existsSync(root)) {\n const { homeSessionId } = await import('../core/orchestrator.js');\n const own = homeSessionId(guard, paths);\n for (const slug of fs.readdirSync(root)) {\n for (const id of fs.readdirSync(path.join(root, slug))) {\n found += 1;\n const mark = id === own ? ' ← 心跳正身' : '';\n console.log(`${id} [${slug}]${mark}`);\n }\n }\n }\n if (found === 0) console.log('(no persisted sessions found)');\n return 0;\n}\n\nasync function verbBind(c: CliCtx): Promise<number> {\n const { guard, paths, sub, rest } = c;\n const { loadBindings, addBinding, removeBinding } = await import('../core/bindings.js');\n switch (sub) {\n case 'list': {\n const data = loadBindings(guard, paths.settingsDir);\n const { homeSessionId } = await import('../core/orchestrator.js');\n const own = homeSessionId(guard, paths);\n if (own) console.log(`心跳正身: ${own}(决策轮次发生地;bind remove 它 = 重置正身)`);\n for (const b of data.bindings) {\n console.log(`${b.sessionId} deliver:${b.deliver ? '√' : '×'} observe:${b.observe ? '√' : '×'}`);\n }\n if (data.bindings.length === 0 && !own) console.log('(no bindings — expressions stay in the dedicated heartbeat session)');\n return 0;\n }\n case 'add': {\n const id = rest[0];\n if (!id || !id.startsWith('session-')) {\n console.error('usage: bind add <sessionId> [--observe] [--no-deliver] (see: sessions list)');\n return 1;\n }\n const observe = rest.includes('--observe') || rest.includes('--observe-only');\n const deliver = !rest.includes('--no-deliver') && !rest.includes('--observe-only');\n const b = addBinding(guard, paths.settingsDir, id, { deliver, observe });\n console.log(`BOUND ${b.sessionId} deliver:${b.deliver} observe:${b.observe}`);\n return 0;\n }\n case 'remove': {\n const id = rest[0];\n if (!id) {\n console.error('usage: bind remove <sessionId>');\n return 1;\n }\n console.log(removeBinding(guard, paths.settingsDir, id) ? `UNBOUND ${id}` : 'NOT_FOUND');\n // Unbinding the HOME session resets it: the next beat creates a fresh\n // dedicated session (the old one goes quiet after restart). H-09/H-45:\n // the shared path also drops the orchestrator's cached agent — the\n // inline delete here used to leave it pointing at the released session.\n const { resetHomeSession } = await import('../core/orchestrator.js');\n if (resetHomeSession(guard, paths, id)) {\n console.log('注意:这是心跳正身会话。已重置——下次心跳将创建新的正身会话(旧会话不再有心跳)');\n }\n return 0;\n }\n default:\n console.error('usage: bind list | add <sessionId> | remove <sessionId>');\n return 1;\n }\n}\n\nasync function verbPreset(c: CliCtx): Promise<number> {\n const { sub, rest, argv } = c;\n const id = flag(argv, '--id') ?? BUNDLED_PRESET_ID;\n // The plugin installs into the roster's own user root; the CLI has no\n // roster, so it reports/uses the conventional one ($DSH_HOME or ~/.dsh).\n const root = conventionalUserPresetRoot();\n const status = presetStatus(import.meta.url, id, root);\n if (sub === undefined || sub === 'status') {\n console.log(`preset id : ${status.id}`);\n console.log(`installed : ${status.installed ? 'yes' : 'no'}`);\n console.log(`target dir : ${status.dir}`);\n console.log(`bundled at : ${status.bundledDir ?? '(not found next to the plugin)'}`);\n if (status.installed) {\n console.log(\n `composition : ${status.compositionMatches ? 'matches the bundled template' : 'differs from the bundled template (hand-edited, or an older version)'}`,\n );\n }\n if (!status.installed) {\n console.log('hint: the plugin installs this itself on the next DSH start (installPreset=true, default);');\n console.log(' or run `preset install` now.');\n }\n return status.installed ? 0 : 1;\n }\n if (sub === 'install') {\n const result = installBundledPreset({\n moduleUrl: import.meta.url,\n id,\n root,\n force: rest.includes('--force'),\n });\n console.log(describeInstall(result));\n return result.action === 'error' ? 1 : 0;\n }\n console.error('usage: preset status | install [--force] [--id <presetId>]');\n return 1;\n}\n\n/** Command table. Adding a verb = one function above plus one line here. */\nconst VERBS: Record<string, Verb> = {\n status: verbStatus,\n seeds: verbSeeds,\n ledger: verbLedger,\n weekly: verbWeekly,\n logs: verbLogs,\n browse: verbBrowse,\n notify: verbNotify,\n profile: verbProfile,\n burn: verbBurn,\n migrate: verbMigrate,\n sessions: verbSessions,\n bind: verbBind,\n preset: verbPreset,\n};\n\nexport async function main(argv: string[]): Promise<number> {\n const [cmd, sub, ...rest] = argv;\n if (!cmd || cmd === 'help' || cmd === '--help') {\n console.log(usage());\n return 0;\n }\n const verb = VERBS[cmd];\n if (!verb) {\n console.error(`unknown command: ${cmd}`);\n console.log(usage());\n return 1;\n }\n const paths = initWorkspace();\n const guard = createPathGuard(paths.dataDir);\n const policy = loadPolicy(guard, paths.configDir, paths.settingsDir);\n const decisionLog = path.join(paths.logsDir, 'heartbeat.jsonl');\n /** Seed lifecycle audit (v1.9.0): CLI edits land in the same log as the beat's. */\n const seedAudit = (entry: Record<string, unknown>): void => {\n try {\n appendAuditLine(decisionLog, entry);\n } catch { /* audit must never break the command */ }\n };\n return verb({\n paths,\n guard,\n policy,\n sub,\n rest,\n argv,\n seedsFile: seedsFilePath(paths.dataDir),\n ledgerFile: ledgerFilePath(paths.dataDir),\n decisionLog,\n seedAudit,\n });\n}\n\nif (process.argv[1] && import.meta.url === new URL(`file:///${process.argv[1].replace(/\\\\/g, '/')}`).href) {\n // Direct execution guard; the CLI is also importable for tests.\n void main(process.argv.slice(2))\n .then((code) => { process.exitCode = code; })\n .catch((e: unknown) => {\n // H-44: no unhandled rejection — print and exit non-zero.\n console.error(e);\n process.exitCode = 1;\n });\n}\n","// Burn list - SINGLE SOURCE OF TRUTH (design doc §10.10; v1 shipped two\n// hardcoded lists and one drifted). burn and uninstall --purge both consume\n// this list. Settings (data/settings/) are NOT burned by default: losing\n// memory != losing the charter/gates the user configured (--all overrides).\n\nimport fs from 'node:fs';\nimport path from 'node:path';\nimport type { PathGuard } from '../core/path-guard.js';\nimport type { WorkspacePaths } from '../core/paths.js';\nimport { shredFileSync } from '../core/atomic-fs.js';\nimport { appendAuditLine } from '../core/audit-log.js';\n\nexport interface BurnTarget {\n /** Relative to dataDir. Files are shredded (overwrite x3) then deleted. */\n file?: string;\n /** Every dataDir file whose name starts with this prefix — a family of\n * timestamped files a bare `file` cannot name (journal archive shards).\n * Shredded like files. */\n prefix?: string;\n /** Directories are removed recursively (no shred - content is files). */\n dir?: string;\n note: string;\n}\n\nexport const BURN_LIST: BurnTarget[] = [\n { file: 'profile.json', note: '画像物化视图' },\n { file: 'profile_inbox.jsonl', note: '观察收件箱' },\n { file: 'profile_journal.jsonl', note: '画像操作流水' },\n // H-19: the rotation shards hold the whole profile history and are written\n // in PLAINTEXT — a burn that leaves them behind leaves the memory readable.\n { prefix: 'profile_journal.archive-', note: '画像流水归档分片(明文;journal 轮转产物)' },\n { file: 'profile_rhythm.json', note: '作息聚合(纯统计)' },\n { file: 'screen.json', note: '屏幕快照(加密)' },\n { file: 'screen.jpg', note: '截图(加密)' },\n { file: 'sent.json', note: '表达记录(加密)' },\n { file: 'browse.json', note: '浏览流状态(加密)' },\n { file: 'seeds.jsonl', note: '素材池(加密)' },\n { file: 'ledger.md', note: '账本(明文,人可读是设计目标)' },\n { file: 'envpulse.json', note: '环境温度计快照' },\n { file: 'gate.json', note: '闸门运行时计数' },\n // v1.9.0 completion (H-19): these carry memory just as much as the rows\n // above — the persona report log records WHAT SHE SAID (spoken / seed_ids /\n // profile_ids / reason), so a burn that skips it is a burn that lies.\n { file: 'profile_snapshot.json', note: '画像快照(journal 轮转基线)' },\n { file: 'cursors.json', note: '观察游标(会话事件位点)' },\n { file: 'seed_report.jsonl', note: '投递报账日志(加密)' },\n { file: 'preference.json', note: '话题偏好统计' },\n { dir: 'weekly', note: '周报(画像与素材散文)' },\n { dir: 'tmp', note: '解锁临时文件(崩溃残留的解密明文是最该烧的东西)' },\n { dir: 'logs', note: '审计与决策日志' },\n { dir: 'exports', note: '导出产物' },\n];\n\nconst SETTINGS_DIR = 'settings'; // excluded unless --all\n\n/** dataDir files matching a prefix target, name-sorted for stable output. */\nfunction prefixMatches(guard: PathGuard, paths: WorkspacePaths, prefix: string): string[] {\n try {\n return fs.readdirSync(guard.assert(paths.dataDir))\n .filter((f) => f.startsWith(prefix))\n .sort();\n } catch {\n return [];\n }\n}\n\nexport interface BurnPlanItem {\n target: BurnTarget;\n exists: boolean;\n}\n\n/** Preview: what exists, what would be removed. No writes. */\nexport function planBurn(guard: PathGuard, paths: WorkspacePaths, all = false): BurnPlanItem[] {\n const plan: BurnPlanItem[] = [];\n for (const t of BURN_LIST) {\n const rel = t.file ?? t.dir ?? t.prefix ?? '';\n if (!all && rel === SETTINGS_DIR) continue;\n let exists = false;\n if (t.prefix) {\n exists = prefixMatches(guard, paths, t.prefix).length > 0;\n } else {\n try {\n exists = fs.existsSync(guard.assert(path.join(paths.dataDir, rel)));\n } catch {\n exists = false;\n }\n }\n plan.push({ target: t, exists });\n }\n if (all) {\n plan.push({ target: { dir: SETTINGS_DIR, note: '用户设定(隐私宪章/闸门参数)——仅 --all 连带' }, exists: fs.existsSync(paths.settingsDir) });\n }\n return plan;\n}\n\n/**\n * Execute the burn: overwrite x3 + delete files, remove dirs. Irreversible.\n * Returns per-target results and writes a BURN_EVENT into the (recreated)\n * journal afterwards - the only trace, on purpose (transparency).\n */\nexport function executeBurn(\n guard: PathGuard,\n paths: WorkspacePaths,\n opts: { all?: boolean; shredPasses?: number } = {},\n): { burned: string[]; missing: string[] } {\n const burned: string[] = [];\n const missing: string[] = [];\n const passes = opts.shredPasses ?? 3;\n for (const t of BURN_LIST) {\n // H-19: a prefix target is a family of files (timestamped archive shards);\n // shred every match individually.\n if (t.prefix) {\n const matches = prefixMatches(guard, paths, t.prefix);\n if (matches.length === 0) {\n missing.push(`${t.prefix}*`);\n continue;\n }\n for (const f of matches) {\n try {\n shredFileSync(guard.assert(path.join(paths.dataDir, f)), passes);\n burned.push(f);\n } catch { /* vanished between listing and shredding: not fatal */ }\n }\n continue;\n }\n const rel = t.file ?? t.dir!;\n const abs = path.join(paths.dataDir, rel);\n let absCanon: string;\n try {\n absCanon = guard.assert(abs);\n } catch {\n missing.push(rel);\n continue;\n }\n if (t.file) {\n if (fs.existsSync(absCanon)) {\n shredFileSync(absCanon, passes);\n burned.push(rel);\n } else {\n missing.push(rel);\n }\n } else if (fs.existsSync(absCanon)) {\n fs.rmSync(absCanon, { recursive: true, force: true });\n burned.push(rel);\n } else {\n missing.push(rel);\n }\n }\n if (opts.all) {\n fs.rmSync(paths.settingsDir, { recursive: true, force: true });\n burned.push(SETTINGS_DIR);\n }\n // BURN_EVENT: recreate the journal; data dir is now re-initializable.\n appendAuditLine(guard.assert(path.join(paths.dataDir, 'profile_journal.jsonl')), {\n event: 'BURN_EVENT',\n burned: burned.length,\n missing: missing.length,\n settingsPreserved: !opts.all,\n });\n return { burned, missing };\n}\n"],"mappings":"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","names":["fs","path","fs","path"]}
1
+ {"version":3,"sources":["../../src/cli/index.ts","../../src/vault/burn-list.ts"],"sourcesContent":["// Operational CLI (design doc §14). Commands grow per module.\n// Run: node dist/cli/index.js <command> [args] (or via tsx in dev)\n//\n// H-42: `main` used to be a 530-line function with a switch holding every\n// verb's body. The verbs are module-level functions now (see CliCtx below) and\n// `main` only builds the shared context and dispatches — one place to add a\n// command, and each verb is readable on its own.\n\nimport { spawn } from 'node:child_process';\nimport fs from 'node:fs';\nimport os from 'node:os';\nimport path from 'node:path';\nimport { initWorkspace } from '../core/paths.js';\nimport type { WorkspacePaths } from '../core/paths.js';\nimport { createPathGuard } from '../core/path-guard.js';\nimport type { PathGuard } from '../core/path-guard.js';\nimport { appendAuditLine, pruneAuditFile } from '../core/audit-log.js';\nimport { atomicWriteFileSync } from '../core/atomic-fs.js';\nimport { loadPolicy } from '../config/load.js';\nimport type { Policy } from '../config/schema.js';\nimport {\n addSeed,\n archiveSeedById,\n gcPool,\n loadPool,\n activeSeeds,\n archivedSeeds,\n seedsFilePath,\n surfaceSeed,\n} from '../seeds/pool.js';\nimport type { SeedSource, SeedTag } from '../seeds/types.js';\nimport {\n appendEntry,\n ledgerFilePath,\n markDone,\n readLedger,\n scanPending,\n} from '../ledger/ledger.js';\nimport {\n adviseWander,\n browseStatus,\n completeWander,\n loadInterests,\n} from '../browse/browse.js';\nimport { ensureRegistered, sendNewMessageHint } from '../notify/notify.js';\nimport {\n loadProfile,\n profileFilePath,\n verifyProfile,\n rebuildProfile,\n} from '../profile/store.js';\nimport { planBurn, executeBurn } from '../vault/burn-list.js';\nimport {\n collectMigrationEntries,\n encryptContainer,\n decryptContainer,\n applyMigrationEntries,\n} from '../vault/migrate.js';\nimport { listWeeklyReports, readWeeklyReport, weeklyDirPath } from '../weekly/report.js';\nimport { writeText } from '../vault/vault.js';\nimport {\n BUNDLED_PRESET_ID,\n conventionalUserPresetRoot,\n describeInstall,\n installBundledPreset,\n presetStatus,\n} from '../core/preset-install.js';\n\nfunction usage(): string {\n return [\n 'usage: heartbeat <command> [args]',\n '',\n 'commands:',\n ' status workspace paths + policy summary',\n ' seeds add <text> [--tag t] [--source s] [--topic x] [--confidence n]',\n ' seeds list [--archived] list active (or archived) seeds',\n ' seeds surface <id> count a surfacing (rule 1 accounting)',\n ' seeds archive <id> deliberate retirement (completed)',\n ' seeds gc run deterministic eviction rules 1-3',\n ' seeds stats pool status JSON',\n ' ledger add <text> register an open item',\n ' ledger list [--pending] list entries',\n ' ledger done <id|substring> mark an entry done',\n ' ledger open open ledger.md in the default editor',\n ' logs cleanup [--dry-run] apply log retention now',\n ' browse status browse state summary (wander)',\n ' browse dry wander adjudication with forced noon window',\n ' browse done <focus> CODE-side registration after a wander visit',\n ' bind list list session bindings (D13)',\n ' bind add <sessionId> [--observe] bind a session (deliver by default)',\n ' bind remove <sessionId> unbind a session',\n ' sessions list enumerate persisted sessions (ids)',\n ' notify check|register|send toast channel (D12: hint only, no body)',\n ' profile list [--all] current valid (or all incl. expired) entries',\n ' profile export decrypted Markdown export to data/exports/',\n ' profile verify journal replay vs disk (report only)',\n ' profile rebuild [--check] rebuild materialized view from journal',\n ' profile snapshot [--force] fold the journal into a snapshot + archive shard',\n ' profile wipe wipe profile data (asks --yes)',\n ' weekly list list generated weekly reports',\n ' weekly show [file] print a report (default: newest)',\n ' migrate export [file] pack memory files into a passphrase container (passphrase: 2 stdin lines)',\n ' migrate import <file> restore a container into this workspace (passphrase: 1 stdin line)',\n ' burn [--yes] [--all] shred runtime data (settings kept unless --all)',\n ' preset status bundled agent preset: target dir + installed?',\n ' preset install [--force] install the bundled preset (never overwrites unless --force)',\n ].join('\\n');\n}\n\nfunction readStdinText(): string {\n try {\n return fs.readFileSync(0, 'utf8').trim();\n } catch {\n return '';\n }\n}\n\nfunction flag(argv: string[], name: string): string | undefined {\n const i = argv.indexOf(name);\n return i > -1 ? argv[i + 1] : undefined;\n}\n\n/** H-42: the seed flags used to be written `flag(rest, '--tag') as never` — the\n * escape hatch threw the type away, so a typo landed in the seed record\n * unchecked. Validate against the known sets instead (the `satisfies` clauses\n * keep these lists in step with the types). */\nconst SEED_TAGS = ['news', 'fandom', 'scene', 'promise'] as const satisfies readonly SeedTag[];\nconst SEED_SOURCES = ['chat', 'screen', 'browse', 'hand', 'profile'] as const satisfies readonly SeedSource[];\n\nfunction flagOneOf<T extends string>(argv: string[], name: string, allowed: readonly T[]): T | undefined {\n const v = flag(argv, name);\n if (v === undefined) return undefined;\n return (allowed as readonly string[]).includes(v) ? (v as T) : undefined;\n}\n\n/** Read N lines from stdin (passphrase prompts for migrate). */\nasync function readLines(prompts: string[]): Promise<string[]> {\n const readline = await import('node:readline/promises');\n const it = readline.createInterface({ input: process.stdin });\n const out: string[] = [];\n for (const p of prompts) out.push((await it.question(p)).trim());\n it.close();\n return out;\n}\n\n/** Everything a verb needs. Built once in {@link main}; `sub`/`rest` are the\n * positional split of argv, `argv` stays available for top-level flags. */\ninterface CliCtx {\n paths: WorkspacePaths;\n guard: PathGuard;\n policy: Policy;\n sub: string | undefined;\n rest: string[];\n argv: string[];\n seedsFile: string;\n ledgerFile: string;\n decisionLog: string;\n seedAudit: (entry: Record<string, unknown>) => void;\n}\n\ntype Verb = (c: CliCtx) => Promise<number>;\n\nasync function verbStatus(c: CliCtx): Promise<number> {\n const { paths, policy } = c;\n console.log(JSON.stringify({\n dataDir: paths.dataDir,\n heartbeatIntervalMin: policy.heartbeat.intervalMin,\n maxDailySend: policy.gate.maxDailySend,\n seedsMaxActive: policy.seeds.maxActive,\n psyEnabled: policy.profile.psyEnabled,\n }, null, 2));\n return 0;\n}\n\nasync function verbSeeds(c: CliCtx): Promise<number> {\n const { guard, policy, sub, rest, seedsFile, seedAudit } = c;\n switch (sub) {\n case 'add': {\n let text = rest[0]?.trim() ?? '';\n if (text === '-') text = readStdinText();\n if (!text) {\n console.error('usage: seeds add <text|-> [--tag t] [--source s] [--topic x] [--confidence n]');\n return 1;\n }\n const result = addSeed(guard, seedsFile, policy, {\n text,\n tag: flagOneOf(rest, '--tag', SEED_TAGS),\n source: flagOneOf(rest, '--source', SEED_SOURCES),\n topic: flag(rest, '--topic'),\n confidence: flag(rest, '--confidence') ? Number(flag(rest, '--confidence')) : undefined,\n }, Date.now(), seedAudit);\n if (result.kind === 'duplicate') {\n console.log(`DUPLICATE: active seed ${result.seed.id} has the same text`);\n return 0;\n }\n console.log(`${result.kind.toUpperCase()} ${result.seed.id}` +\n ` (${activeSeeds(loadPool(guard, seedsFile)).length}/${policy.seeds.maxActive})` +\n (result.evicted ? ` [evicted ${result.evicted.id}: ${result.evicted.retireReason}]` : ''));\n return 0;\n }\n case 'list': {\n const db = loadPool(guard, seedsFile);\n const items = rest.includes('--archived') ? archivedSeeds(db) : activeSeeds(db);\n for (const s of items) {\n const ageDays = Math.floor((Date.now() - Date.parse(s.bornAt)) / 86_400_000);\n console.log(`${s.id} [${s.tag}/${s.source}] d${ageDays} used:${s.used}` +\n `${s.protected ? ' *' : ''} ${s.text.slice(0, 60)}`);\n }\n if (items.length === 0) console.log('(empty)');\n return 0;\n }\n case 'surface': {\n const s = surfaceSeed(guard, seedsFile, policy, rest[0] ?? '', Date.now(), seedAudit);\n if (!s) {\n console.log('NOT_FOUND');\n return 1;\n }\n console.log(`SURFACED ${s.id} used:${s.used}${s.status === 'archived' ? ' -> archived (consumed)' : ''}`);\n return 0;\n }\n case 'archive': {\n const s = archiveSeedById(guard, seedsFile, rest[0] ?? '', 'completed', Date.now(), seedAudit);\n if (!s) {\n console.log('NOT_FOUND');\n return 1;\n }\n console.log(`ARCHIVED ${s.id}`);\n return 0;\n }\n case 'gc': {\n const report = gcPool(guard, seedsFile, policy, Date.now(), seedAudit);\n console.log(`GC consumed:${report.consumed} expired:${report.expired} cold_bench:${report.coldBench}` +\n ` archive_trimmed:${report.archiveTrimmed} -> active ${report.activeAfter}/${policy.seeds.maxActive}` +\n ` archive ${archivedSeeds(loadPool(guard, seedsFile)).length}/${policy.seeds.archiveCap}`);\n return 0;\n }\n case 'stats': {\n const db = loadPool(guard, seedsFile);\n console.log(JSON.stringify({\n active: activeSeeds(db).length,\n archived: archivedSeeds(db).length,\n cap: policy.seeds.maxActive,\n seq: db.seq,\n }, null, 2));\n return 0;\n }\n default:\n console.error(`unknown seeds subcommand: ${sub}`);\n return 1;\n }\n}\n\nasync function verbLedger(c: CliCtx): Promise<number> {\n const { guard, sub, rest, ledgerFile } = c;\n switch (sub) {\n case 'add': {\n let text = rest.join(' ').trim();\n if (text === '-') text = readStdinText();\n if (!text) {\n console.error('usage: ledger add <text|->');\n return 1;\n }\n const e = appendEntry(guard, ledgerFile, text);\n console.log(`OPEN #${e.id} ${e.text.slice(0, 60)}`);\n return 0;\n }\n case 'list': {\n const { entries } = readLedger(guard, ledgerFile);\n const items = rest.includes('--pending') ? scanPending(guard, ledgerFile) : entries;\n for (const e of items) console.log(`${e.status === 'open' ? ' ' : 'x'} #${e.id} ${e.date} ${e.text.slice(0, 60)}`);\n if (items.length === 0) console.log('(empty)');\n return 0;\n }\n case 'done': {\n const key = rest.join(' ').trim();\n if (!key) {\n console.error('usage: ledger done <id|substring>');\n return 1;\n }\n const e = markDone(guard, ledgerFile, key);\n if (!e) {\n console.log('NOT_FOUND');\n return 1;\n }\n console.log(`DONE #${e.id}`);\n return 0;\n }\n case 'open': {\n const f = ledgerFile;\n if (!fs.existsSync(f)) {\n console.log(`(ledger will be created at ${f})`);\n }\n spawn('cmd', ['/c', 'start', '', f], { detached: true, stdio: 'ignore' }).unref();\n console.log(`opened ${f}`);\n return 0;\n }\n default:\n console.error(`unknown ledger subcommand: ${sub}`);\n return 1;\n }\n}\n\nasync function verbWeekly(c: CliCtx): Promise<number> {\n const { guard, paths, sub, rest } = c;\n const reports = listWeeklyReports(guard, paths.dataDir);\n if (sub === 'list' || sub === undefined) {\n if (reports.length === 0) console.log('(no reports yet — heartbeat generates one every 7 days)');\n for (const r of reports) console.log(`${r.file} ${r.start.slice(0, 10)} ~ ${r.end.slice(0, 10)} [${r.source}]`);\n return 0;\n }\n if (sub === 'show') {\n const file = rest[0] ?? reports[0]?.file;\n if (!file) {\n console.log('(no reports yet)');\n return 1;\n }\n const rep = readWeeklyReport(guard, paths.dataDir, file);\n if (!rep) {\n console.error(`no such report: ${file} (see: weekly list; files live in ${weeklyDirPath(paths.dataDir)})`);\n return 1;\n }\n console.log(`# ${rep.start.slice(0, 10)} ~ ${rep.end.slice(0, 10)} [${rep.source}]`);\n console.log(rep.text);\n return 0;\n }\n console.error(`unknown weekly subcommand: ${sub}`);\n return 1;\n}\n\nasync function verbLogs(c: CliCtx): Promise<number> {\n const { paths, policy, sub, rest, decisionLog } = c;\n if (sub !== 'cleanup') {\n console.error('usage: logs cleanup [--dry-run]');\n return 1;\n }\n const dry = rest.includes('--dry-run');\n const envPulse = path.join(paths.logsDir, 'envpulse.jsonl');\n const cut1 = policy.retention.envPulseHours * 3600_000;\n const cut2 = policy.retention.decisionLogDays * 86_400_000;\n if (dry) {\n console.log(`(dry-run) would prune ${envPulse} to ${policy.retention.envPulseHours}h` +\n ` and ${decisionLog} to ${policy.retention.decisionLogDays}d`);\n return 0;\n }\n const a = pruneAuditFile(envPulse, cut1);\n const b = pruneAuditFile(decisionLog, cut2);\n appendAuditLine(decisionLog, { event: 'retention', pruned_envpulse: a, pruned_decision: b });\n console.log(`PRUNED envpulse:${a} decision:${b}`);\n return 0;\n}\n\nasync function verbBrowse(c: CliCtx): Promise<number> {\n const { guard, paths, policy, sub, rest } = c;\n switch (sub) {\n case 'status': {\n const st = browseStatus(guard, paths);\n const interests = loadInterests(paths);\n console.log(JSON.stringify({\n lastWanderAt: st.wander.last_wander_at ? new Date(st.wander.last_wander_at).toISOString() : null,\n focusCount: st.wander.focusCount,\n interestCount: interests.interests?.length ?? 0,\n }, null, 2));\n return 0;\n }\n case 'dry': {\n const forced = new Date();\n forced.setHours(12, 0, 0, 0);\n const advice = adviseWander(guard, paths, policy, forced);\n console.log(JSON.stringify(advice, null, 2));\n return 0;\n }\n case 'done': {\n const focus = rest.join(' ').trim();\n if (!focus) {\n console.error('usage: browse done <focus>');\n return 1;\n }\n const r = completeWander(guard, paths, focus);\n console.log(JSON.stringify(r));\n return 0;\n }\n default:\n console.error(`unknown browse subcommand: ${sub}`);\n return 1;\n }\n}\n\nasync function verbNotify(c: CliCtx): Promise<number> {\n const { paths, sub } = c;\n switch (sub) {\n case 'check':\n console.log(await ensureRegistered(paths) ? 'REGISTERED: yes' : 'REGISTERED: no');\n return 0;\n case 'register':\n await ensureRegistered(paths);\n console.log('register attempted');\n return 0;\n case 'send':\n console.log(await sendNewMessageHint(paths) ? 'SENT' : 'FAILED');\n return 0;\n default:\n console.error('usage: notify check|register|send');\n return 1;\n }\n}\n\nasync function verbProfile(c: CliCtx): Promise<number> {\n const { guard, paths, sub, rest } = c;\n const doc = loadProfile(guard, profileFilePath(paths.dataDir));\n const all = rest.includes('--all');\n switch (sub) {\n case 'list': {\n let n = 0;\n for (const p of ['interest', 'projects', 'comm', 'psy'] as const) {\n for (const e of doc.partitions[p]!.entries) {\n if (!all && e.validTo !== null) continue;\n n += 1;\n console.log(`${e.id} [${e.partition}/${e.topic}/${e.subTopic}] ${e.temporal}` +\n ` conf=${e.confidence.toFixed(2)}${e.lowActivity ? ' 久未验证' : ''}${e.validTo ? ' [失效]' : ''}: ${e.content.slice(0, 60)}`);\n }\n }\n if (n === 0) console.log('(empty)');\n return 0;\n }\n case 'export': {\n const lines = [`# 画像导出 ${new Date().toISOString()}`, ''];\n for (const p of ['interest', 'projects', 'comm', 'psy'] as const) {\n lines.push(`## ${p}`);\n for (const e of doc.partitions[p]!.entries) {\n if (e.validTo !== null) continue;\n lines.push(`- [${e.topic}/${e.subTopic}] ${e.content} (conf ${e.confidence.toFixed(2)}, ${e.temporal})`);\n }\n }\n const out = path.join(paths.exportsDir, `profile-export-${Date.now()}.md`);\n writeText(guard, out, lines.join('\\n') + '\\n');\n console.log(`EXPORTED: ${out}`);\n return 0;\n }\n case 'verify': {\n const r = verifyProfile(guard, paths.dataDir);\n console.log(JSON.stringify(r, null, 2));\n return r.ok ? 0 : 1;\n }\n case 'rebuild': {\n const r = rebuildProfile(guard, paths.dataDir, { check: rest.includes('--check') });\n console.log(JSON.stringify(r, null, 2));\n return r.ok ? 0 : 1;\n }\n case 'wipe': {\n if (!rest.includes('--yes')) {\n console.log('REFUSED: add --yes to wipe profile data (profile.json/inbox/journal)');\n return 1;\n }\n for (const f of ['profile.json', 'profile_inbox.jsonl', 'profile_journal.jsonl']) {\n const abs = guard.assert(path.join(paths.dataDir, f));\n if (fs.existsSync(abs)) fs.rmSync(abs, { force: true });\n }\n console.log('WIPED (settings preserved; use burn for full shredding)');\n return 0;\n }\n case 'snapshot': {\n const { snapshotDue, snapshotProfile, SNAPSHOT_THRESHOLD } = await import('../profile/snapshot.js');\n const { needed, lines } = snapshotDue(guard, paths.dataDir);\n console.log(`journal ${lines} 条(阈值 ${SNAPSHOT_THRESHOLD})`);\n if (!needed && !rest.includes('--force')) {\n console.log('未到阈值,未执行(加 --force 强制折叠)。');\n return 0;\n }\n const report = snapshotProfile(guard, paths.dataDir);\n if (!report.ok) {\n console.log(`未执行:${report.reason}`);\n return 0;\n }\n console.log(`已折叠 ${report.folded} 条 → 快照(baseline ${report.baselineTs}),归档 ${report.archiveFile},live journal 已清空。`);\n console.log('verify/rebuild 自动从快照基点重放,无需额外操作。');\n return 0;\n }\n default:\n console.error(`unknown profile subcommand: ${sub}`);\n return 1;\n }\n}\n\nasync function verbBurn(c: CliCtx): Promise<number> {\n const { guard, paths, rest } = c;\n const yes = rest.includes('--yes');\n const all = rest.includes('--all');\n const plan = planBurn(guard, paths, all);\n console.log('预演(不会执行):');\n for (const p of plan) console.log(` [${p.exists ? '存在' : '无 '}] ${p.target.file ?? p.target.dir} ${p.target.note}`);\n if (!yes) {\n console.log('\\n此操作会让心跳 agent 失忆。确认执行请加 --yes(' + (all ? '含 --all 连用户设定' : '用户设定保留') + ')');\n return 0;\n }\n const result = executeBurn(guard, paths, { all });\n console.log(`BURNED: ${result.burned.length} 项;MISSING: ${result.missing.length} 项`);\n return 0;\n}\n\nasync function verbMigrate(c: CliCtx): Promise<number> {\n const { guard, paths, sub, rest } = c;\n if (sub === 'export') {\n const defaultOut = path.join(paths.exportsDir, `heartbeat-memory-${new Date().toISOString().slice(0, 10)}.hbmig`);\n const outfile = rest[0] ?? defaultOut;\n let outCanon: string;\n try {\n outCanon = guard.assert(outfile);\n } catch {\n console.error(`导出文件必须落在插件 data/ 目录内(路径守卫拒绝):${outfile}\\n默认位置:${defaultOut}`);\n return 1;\n }\n const [pw1, pw2] = await readLines(['设置口令(用于加密迁移包): ', '再输入一次确认: ']);\n if (!pw1 || pw1 !== pw2) {\n console.error('两次输入不一致或为空,已取消。');\n return 1;\n }\n const { entries, progress } = collectMigrationEntries(guard, paths);\n if (entries.length === 0) {\n console.log('没有可打包的记忆文件(data/ 是空的)。');\n return 1;\n }\n fs.mkdirSync(path.dirname(outCanon), { recursive: true });\n atomicWriteFileSync(outCanon, encryptContainer(entries, pw1));\n console.log(`已打包 ${entries.length} 个文件 → ${outCanon}`);\n console.log(` 打包:${progress.packed.join(', ')}`);\n if (progress.missing.length > 0) console.log(` 跳过(不存在):${progress.missing.join(', ')}`);\n console.log('容器是口令加密的,可安全拷贝到新机器;DPAPI 会在导入时用新机器重新加密。');\n return 0;\n }\n if (sub === 'import') {\n const infile = rest[0];\n if (!infile) {\n console.error('usage: migrate import <container-file>');\n return 1;\n }\n const [pw] = await readLines(['输入迁移包口令: ']);\n let text: string;\n try {\n text = fs.readFileSync(infile, 'utf8');\n } catch {\n console.error(`读不到迁移包:${infile}`);\n return 1;\n }\n let files;\n try {\n files = decryptContainer(text, pw ?? '');\n } catch (e) {\n console.error(String(e instanceof Error ? e.message : e));\n return 1;\n }\n const result = applyMigrationEntries(guard, paths, files.files);\n console.log(`恢复 ${result.restored.length} 个文件;备份 ${result.backedUp.length} 个被覆盖文件;跳过 ${result.skipped.length} 个。`);\n for (const r of result.restored) console.log(` 恢复: ${r}`);\n for (const b of result.backedUp) console.log(` 备份: ${b}.bak-migrate-*`);\n if (result.skipped.length > 0) console.log(` 跳过: ${result.skipped.join(', ')}`);\n if (result.error) console.log(` 失败并已回滚:${result.error}`);\n console.log('重启 DSH 后生效。');\n return result.error ? 1 : 0;\n }\n console.error(`unknown migrate subcommand: ${sub}`);\n return 1;\n}\n\nasync function verbSessions(c: CliCtx): Promise<number> {\n const { guard, paths } = c;\n // Read-only enumeration of the host's persisted sessions (ids from the\n // on-disk store; titles live server-side and are not listed here).\n const root = path.join(os.homedir(), '.dsh', 'sessions');\n let found = 0;\n if (fs.existsSync(root)) {\n const { homeSessionId } = await import('../core/orchestrator.js');\n const own = homeSessionId(guard, paths);\n for (const slug of fs.readdirSync(root)) {\n for (const id of fs.readdirSync(path.join(root, slug))) {\n found += 1;\n const mark = id === own ? ' ← 心跳正身' : '';\n console.log(`${id} [${slug}]${mark}`);\n }\n }\n }\n if (found === 0) console.log('(no persisted sessions found)');\n return 0;\n}\n\nasync function verbBind(c: CliCtx): Promise<number> {\n const { guard, paths, sub, rest } = c;\n const { loadBindings, addBinding, removeBinding } = await import('../core/bindings.js');\n switch (sub) {\n case 'list': {\n const data = loadBindings(guard, paths.settingsDir);\n const { homeSessionId } = await import('../core/orchestrator.js');\n const own = homeSessionId(guard, paths);\n if (own) console.log(`心跳正身: ${own}(决策轮次发生地;bind remove 它 = 重置正身)`);\n for (const b of data.bindings) {\n console.log(`${b.sessionId} deliver:${b.deliver ? '√' : '×'} observe:${b.observe ? '√' : '×'}`);\n }\n if (data.bindings.length === 0 && !own) console.log('(no bindings — expressions stay in the dedicated heartbeat session)');\n return 0;\n }\n case 'add': {\n const id = rest[0];\n if (!id || !id.startsWith('session-')) {\n console.error('usage: bind add <sessionId> [--observe] [--no-deliver] (see: sessions list)');\n return 1;\n }\n const observe = rest.includes('--observe') || rest.includes('--observe-only');\n const deliver = !rest.includes('--no-deliver') && !rest.includes('--observe-only');\n const b = addBinding(guard, paths.settingsDir, id, { deliver, observe });\n console.log(`BOUND ${b.sessionId} deliver:${b.deliver} observe:${b.observe}`);\n return 0;\n }\n case 'remove': {\n const id = rest[0];\n if (!id) {\n console.error('usage: bind remove <sessionId>');\n return 1;\n }\n console.log(removeBinding(guard, paths.settingsDir, id) ? `UNBOUND ${id}` : 'NOT_FOUND');\n // Unbinding the HOME session resets it: the next beat creates a fresh\n // dedicated session (the old one goes quiet after restart). H-09/H-45:\n // the shared path also drops the orchestrator's cached agent — the\n // inline delete here used to leave it pointing at the released session.\n const { resetHomeSession } = await import('../core/orchestrator.js');\n if (resetHomeSession(guard, paths, id)) {\n console.log('注意:这是心跳正身会话。已重置——下次心跳将创建新的正身会话(旧会话不再有心跳)');\n }\n return 0;\n }\n default:\n console.error('usage: bind list | add <sessionId> | remove <sessionId>');\n return 1;\n }\n}\n\nasync function verbPreset(c: CliCtx): Promise<number> {\n const { sub, rest, argv } = c;\n const id = flag(argv, '--id') ?? BUNDLED_PRESET_ID;\n // The plugin installs into the roster's own user root; the CLI has no\n // roster, so it reports/uses the conventional one ($DSH_HOME or ~/.dsh).\n const root = conventionalUserPresetRoot();\n const status = presetStatus(import.meta.url, id, root);\n if (sub === undefined || sub === 'status') {\n console.log(`preset id : ${status.id}`);\n console.log(`installed : ${status.installed ? 'yes' : 'no'}`);\n console.log(`target dir : ${status.dir}`);\n console.log(`bundled at : ${status.bundledDir ?? '(not found next to the plugin)'}`);\n if (status.installed) {\n console.log(\n `composition : ${status.compositionMatches ? 'matches the bundled template' : 'differs from the bundled template (hand-edited, or an older version)'}`,\n );\n }\n if (!status.installed) {\n console.log('hint: the plugin installs this itself on the next DSH start (installPreset=true, default);');\n console.log(' or run `preset install` now.');\n }\n return status.installed ? 0 : 1;\n }\n if (sub === 'install') {\n const result = installBundledPreset({\n moduleUrl: import.meta.url,\n id,\n root,\n force: rest.includes('--force'),\n });\n console.log(describeInstall(result));\n return result.action === 'error' ? 1 : 0;\n }\n console.error('usage: preset status | install [--force] [--id <presetId>]');\n return 1;\n}\n\n/** Command table. Adding a verb = one function above plus one line here. */\nconst VERBS: Record<string, Verb> = {\n status: verbStatus,\n seeds: verbSeeds,\n ledger: verbLedger,\n weekly: verbWeekly,\n logs: verbLogs,\n browse: verbBrowse,\n notify: verbNotify,\n profile: verbProfile,\n burn: verbBurn,\n migrate: verbMigrate,\n sessions: verbSessions,\n bind: verbBind,\n preset: verbPreset,\n};\n\nexport async function main(argv: string[]): Promise<number> {\n const [cmd, sub, ...rest] = argv;\n if (!cmd || cmd === 'help' || cmd === '--help') {\n console.log(usage());\n return 0;\n }\n const verb = VERBS[cmd];\n if (!verb) {\n console.error(`unknown command: ${cmd}`);\n console.log(usage());\n return 1;\n }\n const paths = initWorkspace();\n const guard = createPathGuard(paths.dataDir);\n const policy = loadPolicy(guard, paths.configDir, paths.settingsDir);\n const decisionLog = path.join(paths.logsDir, 'heartbeat.jsonl');\n /** Seed lifecycle audit (v1.9.0): CLI edits land in the same log as the beat's. */\n const seedAudit = (entry: Record<string, unknown>): void => {\n try {\n appendAuditLine(decisionLog, entry);\n } catch { /* audit must never break the command */ }\n };\n return verb({\n paths,\n guard,\n policy,\n sub,\n rest,\n argv,\n seedsFile: seedsFilePath(paths.dataDir),\n ledgerFile: ledgerFilePath(paths.dataDir),\n decisionLog,\n seedAudit,\n });\n}\n\nif (process.argv[1] && import.meta.url === new URL(`file:///${process.argv[1].replace(/\\\\/g, '/')}`).href) {\n // Direct execution guard; the CLI is also importable for tests.\n void main(process.argv.slice(2))\n .then((code) => { process.exitCode = code; })\n .catch((e: unknown) => {\n // H-44: no unhandled rejection — print and exit non-zero.\n console.error(e);\n process.exitCode = 1;\n });\n}\n","// Burn list - SINGLE SOURCE OF TRUTH (design doc §10.10; v1 shipped two\r\n// hardcoded lists and one drifted). burn and uninstall --purge both consume\r\n// this list. Settings (data/settings/) are NOT burned by default: losing\r\n// memory != losing the charter/gates the user configured (--all overrides).\r\n\r\nimport fs from 'node:fs';\r\nimport path from 'node:path';\r\nimport type { PathGuard } from '../core/path-guard.js';\r\nimport type { WorkspacePaths } from '../core/paths.js';\r\nimport { shredFileSync } from '../core/atomic-fs.js';\r\nimport { appendAuditLine } from '../core/audit-log.js';\r\n\r\nexport interface BurnTarget {\r\n /** Relative to dataDir. Files are shredded (overwrite x3) then deleted. */\r\n file?: string;\r\n /** Every dataDir file whose name starts with this prefix — a family of\r\n * timestamped files a bare `file` cannot name (journal archive shards).\r\n * Shredded like files. */\r\n prefix?: string;\r\n /** Directories are removed recursively (no shred - content is files). */\r\n dir?: string;\r\n note: string;\r\n}\r\n\r\nexport const BURN_LIST: BurnTarget[] = [\r\n { file: 'profile.json', note: '画像物化视图' },\r\n { file: 'profile_inbox.jsonl', note: '观察收件箱' },\r\n { file: 'profile_journal.jsonl', note: '画像操作流水' },\r\n // H-19: the rotation shards hold the whole profile history and are written\r\n // in PLAINTEXT — a burn that leaves them behind leaves the memory readable.\r\n { prefix: 'profile_journal.archive-', note: '画像流水归档分片(明文;journal 轮转产物)' },\r\n { file: 'profile_rhythm.json', note: '作息聚合(纯统计)' },\r\n { file: 'screen.json', note: '屏幕快照(加密)' },\r\n { file: 'screen.jpg', note: '截图(加密)' },\r\n { file: 'sent.json', note: '表达记录(加密)' },\r\n { file: 'browse.json', note: '浏览流状态(加密)' },\r\n { file: 'seeds.jsonl', note: '素材池(加密)' },\r\n { file: 'ledger.md', note: '账本(明文,人可读是设计目标)' },\r\n { file: 'envpulse.json', note: '环境温度计快照' },\r\n { file: 'gate.json', note: '闸门运行时计数' },\r\n // v1.9.0 completion (H-19): these carry memory just as much as the rows\r\n // above — the persona report log records WHAT SHE SAID (spoken / seed_ids /\r\n // profile_ids / reason), so a burn that skips it is a burn that lies.\r\n { file: 'profile_snapshot.json', note: '画像快照(journal 轮转基线)' },\r\n { file: 'cursors.json', note: '观察游标(会话事件位点)' },\r\n { file: 'seed_report.jsonl', note: '投递报账日志(加密)' },\r\n { file: 'preference.json', note: '话题偏好统计' },\r\n { dir: 'weekly', note: '周报(画像与素材散文)' },\r\n { dir: 'tmp', note: '解锁临时文件(崩溃残留的解密明文是最该烧的东西)' },\r\n { dir: 'logs', note: '审计与决策日志' },\r\n { dir: 'exports', note: '导出产物' },\r\n];\r\n\r\nconst SETTINGS_DIR = 'settings'; // excluded unless --all\r\n\r\n/** dataDir files matching a prefix target, name-sorted for stable output. */\r\nfunction prefixMatches(guard: PathGuard, paths: WorkspacePaths, prefix: string): string[] {\r\n try {\r\n return fs.readdirSync(guard.assert(paths.dataDir))\r\n .filter((f) => f.startsWith(prefix))\r\n .sort();\r\n } catch {\r\n return [];\r\n }\r\n}\r\n\r\nexport interface BurnPlanItem {\r\n target: BurnTarget;\r\n exists: boolean;\r\n}\r\n\r\n/** Preview: what exists, what would be removed. No writes. */\r\nexport function planBurn(guard: PathGuard, paths: WorkspacePaths, all = false): BurnPlanItem[] {\r\n const plan: BurnPlanItem[] = [];\r\n for (const t of BURN_LIST) {\r\n const rel = t.file ?? t.dir ?? t.prefix ?? '';\r\n if (!all && rel === SETTINGS_DIR) continue;\r\n let exists = false;\r\n if (t.prefix) {\r\n exists = prefixMatches(guard, paths, t.prefix).length > 0;\r\n } else {\r\n try {\r\n exists = fs.existsSync(guard.assert(path.join(paths.dataDir, rel)));\r\n } catch {\r\n exists = false;\r\n }\r\n }\r\n plan.push({ target: t, exists });\r\n }\r\n if (all) {\r\n plan.push({ target: { dir: SETTINGS_DIR, note: '用户设定(隐私宪章/闸门参数)——仅 --all 连带' }, exists: fs.existsSync(paths.settingsDir) });\r\n }\r\n return plan;\r\n}\r\n\r\n/**\r\n * Execute the burn: overwrite x3 + delete files, remove dirs. Irreversible.\r\n * Returns per-target results and writes a BURN_EVENT into the (recreated)\r\n * journal afterwards - the only trace, on purpose (transparency).\r\n */\r\nexport function executeBurn(\r\n guard: PathGuard,\r\n paths: WorkspacePaths,\r\n opts: { all?: boolean; shredPasses?: number } = {},\r\n): { burned: string[]; missing: string[] } {\r\n const burned: string[] = [];\r\n const missing: string[] = [];\r\n const passes = opts.shredPasses ?? 3;\r\n for (const t of BURN_LIST) {\r\n // H-19: a prefix target is a family of files (timestamped archive shards);\r\n // shred every match individually.\r\n if (t.prefix) {\r\n const matches = prefixMatches(guard, paths, t.prefix);\r\n if (matches.length === 0) {\r\n missing.push(`${t.prefix}*`);\r\n continue;\r\n }\r\n for (const f of matches) {\r\n try {\r\n shredFileSync(guard.assert(path.join(paths.dataDir, f)), passes);\r\n burned.push(f);\r\n } catch { /* vanished between listing and shredding: not fatal */ }\r\n }\r\n continue;\r\n }\r\n const rel = t.file ?? t.dir!;\r\n const abs = path.join(paths.dataDir, rel);\r\n let absCanon: string;\r\n try {\r\n absCanon = guard.assert(abs);\r\n } catch {\r\n missing.push(rel);\r\n continue;\r\n }\r\n if (t.file) {\r\n if (fs.existsSync(absCanon)) {\r\n shredFileSync(absCanon, passes);\r\n burned.push(rel);\r\n } else {\r\n missing.push(rel);\r\n }\r\n } else if (fs.existsSync(absCanon)) {\r\n fs.rmSync(absCanon, { recursive: true, force: true });\r\n burned.push(rel);\r\n } else {\r\n missing.push(rel);\r\n }\r\n }\r\n if (opts.all) {\r\n fs.rmSync(paths.settingsDir, { recursive: true, force: true });\r\n burned.push(SETTINGS_DIR);\r\n }\r\n // BURN_EVENT: recreate the journal; data dir is now re-initializable.\r\n appendAuditLine(guard.assert(path.join(paths.dataDir, 'profile_journal.jsonl')), {\r\n event: 'BURN_EVENT',\r\n burned: burned.length,\r\n missing: missing.length,\r\n settingsPreserved: !opts.all,\r\n });\r\n return { burned, missing };\r\n}\r\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAQA,SAAS,aAAa;AACtB,OAAOA,SAAQ;AACf,OAAO,QAAQ;AACf,OAAOC,WAAU;;;ACNjB,OAAO,QAAQ;AACf,OAAO,UAAU;AAkBV,IAAM,YAA0B;AAAA,EACrC,EAAE,MAAM,gBAAgB,MAAM,uCAAS;AAAA,EACvC,EAAE,MAAM,uBAAuB,MAAM,iCAAQ;AAAA,EAC7C,EAAE,MAAM,yBAAyB,MAAM,uCAAS;AAAA;AAAA;AAAA,EAGhD,EAAE,QAAQ,4BAA4B,MAAM,iHAA4B;AAAA,EACxE,EAAE,MAAM,uBAAuB,MAAM,yDAAY;AAAA,EACjD,EAAE,MAAM,eAAe,MAAM,mDAAW;AAAA,EACxC,EAAE,MAAM,cAAc,MAAM,uCAAS;AAAA,EACrC,EAAE,MAAM,aAAa,MAAM,mDAAW;AAAA,EACtC,EAAE,MAAM,eAAe,MAAM,yDAAY;AAAA,EACzC,EAAE,MAAM,eAAe,MAAM,6CAAU;AAAA,EACvC,EAAE,MAAM,aAAa,MAAM,6FAAkB;AAAA,EAC7C,EAAE,MAAM,iBAAiB,MAAM,6CAAU;AAAA,EACzC,EAAE,MAAM,aAAa,MAAM,6CAAU;AAAA;AAAA;AAAA;AAAA,EAIrC,EAAE,MAAM,yBAAyB,MAAM,uEAAqB;AAAA,EAC5D,EAAE,MAAM,gBAAgB,MAAM,2EAAe;AAAA,EAC7C,EAAE,MAAM,qBAAqB,MAAM,+DAAa;AAAA,EAChD,EAAE,MAAM,mBAAmB,MAAM,uCAAS;AAAA,EAC1C,EAAE,KAAK,UAAU,MAAM,qEAAc;AAAA,EACrC,EAAE,KAAK,OAAO,MAAM,mJAA2B;AAAA,EAC/C,EAAE,KAAK,QAAQ,MAAM,6CAAU;AAAA,EAC/B,EAAE,KAAK,WAAW,MAAM,2BAAO;AACjC;AAEA,IAAM,eAAe;AAGrB,SAAS,cAAc,OAAkB,OAAuB,QAA0B;AACxF,MAAI;AACF,WAAO,GAAG,YAAY,MAAM,OAAO,MAAM,OAAO,CAAC,EAC9C,OAAO,CAAC,MAAM,EAAE,WAAW,MAAM,CAAC,EAClC,KAAK;AAAA,EACV,QAAQ;AACN,WAAO,CAAC;AAAA,EACV;AACF;AAQO,SAAS,SAAS,OAAkB,OAAuB,MAAM,OAAuB;AAC7F,QAAM,OAAuB,CAAC;AAC9B,aAAW,KAAK,WAAW;AACzB,UAAM,MAAM,EAAE,QAAQ,EAAE,OAAO,EAAE,UAAU;AAC3C,QAAI,CAAC,OAAO,QAAQ,aAAc;AAClC,QAAI,SAAS;AACb,QAAI,EAAE,QAAQ;AACZ,eAAS,cAAc,OAAO,OAAO,EAAE,MAAM,EAAE,SAAS;AAAA,IAC1D,OAAO;AACL,UAAI;AACF,iBAAS,GAAG,WAAW,MAAM,OAAO,KAAK,KAAK,MAAM,SAAS,GAAG,CAAC,CAAC;AAAA,MACpE,QAAQ;AACN,iBAAS;AAAA,MACX;AAAA,IACF;AACA,SAAK,KAAK,EAAE,QAAQ,GAAG,OAAO,CAAC;AAAA,EACjC;AACA,MAAI,KAAK;AACP,SAAK,KAAK,EAAE,QAAQ,EAAE,KAAK,cAAc,MAAM,6HAA8B,GAAG,QAAQ,GAAG,WAAW,MAAM,WAAW,EAAE,CAAC;AAAA,EAC5H;AACA,SAAO;AACT;AAOO,SAAS,YACd,OACA,OACA,OAAgD,CAAC,GACR;AACzC,QAAM,SAAmB,CAAC;AAC1B,QAAM,UAAoB,CAAC;AAC3B,QAAM,SAAS,KAAK,eAAe;AACnC,aAAW,KAAK,WAAW;AAGzB,QAAI,EAAE,QAAQ;AACZ,YAAM,UAAU,cAAc,OAAO,OAAO,EAAE,MAAM;AACpD,UAAI,QAAQ,WAAW,GAAG;AACxB,gBAAQ,KAAK,GAAG,EAAE,MAAM,GAAG;AAC3B;AAAA,MACF;AACA,iBAAW,KAAK,SAAS;AACvB,YAAI;AACF,wBAAc,MAAM,OAAO,KAAK,KAAK,MAAM,SAAS,CAAC,CAAC,GAAG,MAAM;AAC/D,iBAAO,KAAK,CAAC;AAAA,QACf,QAAQ;AAAA,QAA0D;AAAA,MACpE;AACA;AAAA,IACF;AACA,UAAM,MAAM,EAAE,QAAQ,EAAE;AACxB,UAAM,MAAM,KAAK,KAAK,MAAM,SAAS,GAAG;AACxC,QAAI;AACJ,QAAI;AACF,iBAAW,MAAM,OAAO,GAAG;AAAA,IAC7B,QAAQ;AACN,cAAQ,KAAK,GAAG;AAChB;AAAA,IACF;AACA,QAAI,EAAE,MAAM;AACV,UAAI,GAAG,WAAW,QAAQ,GAAG;AAC3B,sBAAc,UAAU,MAAM;AAC9B,eAAO,KAAK,GAAG;AAAA,MACjB,OAAO;AACL,gBAAQ,KAAK,GAAG;AAAA,MAClB;AAAA,IACF,WAAW,GAAG,WAAW,QAAQ,GAAG;AAClC,SAAG,OAAO,UAAU,EAAE,WAAW,MAAM,OAAO,KAAK,CAAC;AACpD,aAAO,KAAK,GAAG;AAAA,IACjB,OAAO;AACL,cAAQ,KAAK,GAAG;AAAA,IAClB;AAAA,EACF;AACA,MAAI,KAAK,KAAK;AACZ,OAAG,OAAO,MAAM,aAAa,EAAE,WAAW,MAAM,OAAO,KAAK,CAAC;AAC7D,WAAO,KAAK,YAAY;AAAA,EAC1B;AAEA,kBAAgB,MAAM,OAAO,KAAK,KAAK,MAAM,SAAS,uBAAuB,CAAC,GAAG;AAAA,IAC/E,OAAO;AAAA,IACP,QAAQ,OAAO;AAAA,IACf,SAAS,QAAQ;AAAA,IACjB,mBAAmB,CAAC,KAAK;AAAA,EAC3B,CAAC;AACD,SAAO,EAAE,QAAQ,QAAQ;AAC3B;;;AD5FA,SAAS,QAAgB;AACvB,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF,EAAE,KAAK,IAAI;AACb;AAEA,SAAS,gBAAwB;AAC/B,MAAI;AACF,WAAOC,IAAG,aAAa,GAAG,MAAM,EAAE,KAAK;AAAA,EACzC,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAEA,SAAS,KAAK,MAAgB,MAAkC;AAC9D,QAAM,IAAI,KAAK,QAAQ,IAAI;AAC3B,SAAO,IAAI,KAAK,KAAK,IAAI,CAAC,IAAI;AAChC;AAMA,IAAM,YAAY,CAAC,QAAQ,UAAU,SAAS,SAAS;AACvD,IAAM,eAAe,CAAC,QAAQ,UAAU,UAAU,QAAQ,SAAS;AAEnE,SAAS,UAA4B,MAAgB,MAAc,SAAsC;AACvG,QAAM,IAAI,KAAK,MAAM,IAAI;AACzB,MAAI,MAAM,OAAW,QAAO;AAC5B,SAAQ,QAA8B,SAAS,CAAC,IAAK,IAAU;AACjE;AAGA,eAAe,UAAU,SAAsC;AAC7D,QAAM,WAAW,MAAM,OAAO,mBAAwB;AACtD,QAAM,KAAK,SAAS,gBAAgB,EAAE,OAAO,QAAQ,MAAM,CAAC;AAC5D,QAAM,MAAgB,CAAC;AACvB,aAAW,KAAK,QAAS,KAAI,MAAM,MAAM,GAAG,SAAS,CAAC,GAAG,KAAK,CAAC;AAC/D,KAAG,MAAM;AACT,SAAO;AACT;AAmBA,eAAe,WAAW,GAA4B;AACpD,QAAM,EAAE,OAAO,OAAO,IAAI;AAC1B,UAAQ,IAAI,KAAK,UAAU;AAAA,IACzB,SAAS,MAAM;AAAA,IACf,sBAAsB,OAAO,UAAU;AAAA,IACvC,cAAc,OAAO,KAAK;AAAA,IAC1B,gBAAgB,OAAO,MAAM;AAAA,IAC7B,YAAY,OAAO,QAAQ;AAAA,EAC7B,GAAG,MAAM,CAAC,CAAC;AACX,SAAO;AACT;AAEA,eAAe,UAAU,GAA4B;AACnD,QAAM,EAAE,OAAO,QAAQ,KAAK,MAAM,WAAW,UAAU,IAAI;AAC3D,UAAQ,KAAK;AAAA,IACX,KAAK,OAAO;AACV,UAAI,OAAO,KAAK,CAAC,GAAG,KAAK,KAAK;AAC9B,UAAI,SAAS,IAAK,QAAO,cAAc;AACvC,UAAI,CAAC,MAAM;AACT,gBAAQ,MAAM,+EAA+E;AAC7F,eAAO;AAAA,MACT;AACA,YAAM,SAAS,QAAQ,OAAO,WAAW,QAAQ;AAAA,QAC/C;AAAA,QACA,KAAK,UAAU,MAAM,SAAS,SAAS;AAAA,QACvC,QAAQ,UAAU,MAAM,YAAY,YAAY;AAAA,QAChD,OAAO,KAAK,MAAM,SAAS;AAAA,QAC3B,YAAY,KAAK,MAAM,cAAc,IAAI,OAAO,KAAK,MAAM,cAAc,CAAC,IAAI;AAAA,MAChF,GAAG,KAAK,IAAI,GAAG,SAAS;AACxB,UAAI,OAAO,SAAS,aAAa;AAC/B,gBAAQ,IAAI,0BAA0B,OAAO,KAAK,EAAE,oBAAoB;AACxE,eAAO;AAAA,MACT;AACA,cAAQ,IAAI,GAAG,OAAO,KAAK,YAAY,CAAC,IAAI,OAAO,KAAK,EAAE,KACnD,YAAY,SAAS,OAAO,SAAS,CAAC,EAAE,MAAM,IAAI,OAAO,MAAM,SAAS,OAC5E,OAAO,UAAU,aAAa,OAAO,QAAQ,EAAE,KAAK,OAAO,QAAQ,YAAY,MAAM,GAAG;AAC3F,aAAO;AAAA,IACT;AAAA,IACA,KAAK,QAAQ;AACX,YAAM,KAAK,SAAS,OAAO,SAAS;AACpC,YAAM,QAAQ,KAAK,SAAS,YAAY,IAAI,cAAc,EAAE,IAAI,YAAY,EAAE;AAC9E,iBAAW,KAAK,OAAO;AACrB,cAAM,UAAU,KAAK,OAAO,KAAK,IAAI,IAAI,KAAK,MAAM,EAAE,MAAM,KAAK,KAAU;AAC3E,gBAAQ,IAAI,GAAG,EAAE,EAAE,KAAK,EAAE,GAAG,IAAI,EAAE,MAAM,MAAM,OAAO,SAAS,EAAE,IAAI,GAChE,EAAE,YAAY,OAAO,EAAE,IAAI,EAAE,KAAK,MAAM,GAAG,EAAE,CAAC,EAAE;AAAA,MACvD;AACA,UAAI,MAAM,WAAW,EAAG,SAAQ,IAAI,SAAS;AAC7C,aAAO;AAAA,IACT;AAAA,IACA,KAAK,WAAW;AACd,YAAM,IAAI,YAAY,OAAO,WAAW,QAAQ,KAAK,CAAC,KAAK,IAAI,KAAK,IAAI,GAAG,SAAS;AACpF,UAAI,CAAC,GAAG;AACN,gBAAQ,IAAI,WAAW;AACvB,eAAO;AAAA,MACT;AACA,cAAQ,IAAI,YAAY,EAAE,EAAE,SAAS,EAAE,IAAI,GAAG,EAAE,WAAW,aAAa,4BAA4B,EAAE,EAAE;AACxG,aAAO;AAAA,IACT;AAAA,IACA,KAAK,WAAW;AACd,YAAM,IAAI,gBAAgB,OAAO,WAAW,KAAK,CAAC,KAAK,IAAI,aAAa,KAAK,IAAI,GAAG,SAAS;AAC7F,UAAI,CAAC,GAAG;AACN,gBAAQ,IAAI,WAAW;AACvB,eAAO;AAAA,MACT;AACA,cAAQ,IAAI,YAAY,EAAE,EAAE,EAAE;AAC9B,aAAO;AAAA,IACT;AAAA,IACA,KAAK,MAAM;AACT,YAAM,SAAS,OAAO,OAAO,WAAW,QAAQ,KAAK,IAAI,GAAG,SAAS;AACrE,cAAQ,IAAI,eAAe,OAAO,QAAQ,YAAY,OAAO,OAAO,eAAe,OAAO,SAAS,oBAC7E,OAAO,cAAc,cAAc,OAAO,WAAW,IAAI,OAAO,MAAM,SAAS,YACvF,cAAc,SAAS,OAAO,SAAS,CAAC,EAAE,MAAM,IAAI,OAAO,MAAM,UAAU,EAAE;AAC3F,aAAO;AAAA,IACT;AAAA,IACA,KAAK,SAAS;AACZ,YAAM,KAAK,SAAS,OAAO,SAAS;AACpC,cAAQ,IAAI,KAAK,UAAU;AAAA,QACzB,QAAQ,YAAY,EAAE,EAAE;AAAA,QACxB,UAAU,cAAc,EAAE,EAAE;AAAA,QAC5B,KAAK,OAAO,MAAM;AAAA,QAClB,KAAK,GAAG;AAAA,MACV,GAAG,MAAM,CAAC,CAAC;AACX,aAAO;AAAA,IACT;AAAA,IACA;AACE,cAAQ,MAAM,6BAA6B,GAAG,EAAE;AAChD,aAAO;AAAA,EACX;AACF;AAEA,eAAe,WAAW,GAA4B;AACpD,QAAM,EAAE,OAAO,KAAK,MAAM,WAAW,IAAI;AACzC,UAAQ,KAAK;AAAA,IACX,KAAK,OAAO;AACV,UAAI,OAAO,KAAK,KAAK,GAAG,EAAE,KAAK;AAC/B,UAAI,SAAS,IAAK,QAAO,cAAc;AACvC,UAAI,CAAC,MAAM;AACT,gBAAQ,MAAM,4BAA4B;AAC1C,eAAO;AAAA,MACT;AACA,YAAM,IAAI,YAAY,OAAO,YAAY,IAAI;AAC7C,cAAQ,IAAI,SAAS,EAAE,EAAE,IAAI,EAAE,KAAK,MAAM,GAAG,EAAE,CAAC,EAAE;AAClD,aAAO;AAAA,IACT;AAAA,IACA,KAAK,QAAQ;AACX,YAAM,EAAE,QAAQ,IAAI,WAAW,OAAO,UAAU;AAChD,YAAM,QAAQ,KAAK,SAAS,WAAW,IAAI,YAAY,OAAO,UAAU,IAAI;AAC5E,iBAAW,KAAK,MAAO,SAAQ,IAAI,GAAG,EAAE,WAAW,SAAS,MAAM,GAAG,KAAK,EAAE,EAAE,IAAI,EAAE,IAAI,IAAI,EAAE,KAAK,MAAM,GAAG,EAAE,CAAC,EAAE;AACjH,UAAI,MAAM,WAAW,EAAG,SAAQ,IAAI,SAAS;AAC7C,aAAO;AAAA,IACT;AAAA,IACA,KAAK,QAAQ;AACX,YAAM,MAAM,KAAK,KAAK,GAAG,EAAE,KAAK;AAChC,UAAI,CAAC,KAAK;AACR,gBAAQ,MAAM,mCAAmC;AACjD,eAAO;AAAA,MACT;AACA,YAAM,IAAI,SAAS,OAAO,YAAY,GAAG;AACzC,UAAI,CAAC,GAAG;AACN,gBAAQ,IAAI,WAAW;AACvB,eAAO;AAAA,MACT;AACA,cAAQ,IAAI,SAAS,EAAE,EAAE,EAAE;AAC3B,aAAO;AAAA,IACT;AAAA,IACA,KAAK,QAAQ;AACX,YAAM,IAAI;AACV,UAAI,CAACA,IAAG,WAAW,CAAC,GAAG;AACrB,gBAAQ,IAAI,8BAA8B,CAAC,GAAG;AAAA,MAChD;AACA,YAAM,OAAO,CAAC,MAAM,SAAS,IAAI,CAAC,GAAG,EAAE,UAAU,MAAM,OAAO,SAAS,CAAC,EAAE,MAAM;AAChF,cAAQ,IAAI,UAAU,CAAC,EAAE;AACzB,aAAO;AAAA,IACT;AAAA,IACA;AACE,cAAQ,MAAM,8BAA8B,GAAG,EAAE;AACjD,aAAO;AAAA,EACX;AACF;AAEA,eAAe,WAAW,GAA4B;AACpD,QAAM,EAAE,OAAO,OAAO,KAAK,KAAK,IAAI;AACpC,QAAM,UAAU,kBAAkB,OAAO,MAAM,OAAO;AACtD,MAAI,QAAQ,UAAU,QAAQ,QAAW;AACvC,QAAI,QAAQ,WAAW,EAAG,SAAQ,IAAI,8DAAyD;AAC/F,eAAW,KAAK,QAAS,SAAQ,IAAI,GAAG,EAAE,IAAI,KAAK,EAAE,MAAM,MAAM,GAAG,EAAE,CAAC,MAAM,EAAE,IAAI,MAAM,GAAG,EAAE,CAAC,MAAM,EAAE,MAAM,GAAG;AAChH,WAAO;AAAA,EACT;AACA,MAAI,QAAQ,QAAQ;AAClB,UAAM,OAAO,KAAK,CAAC,KAAK,QAAQ,CAAC,GAAG;AACpC,QAAI,CAAC,MAAM;AACT,cAAQ,IAAI,kBAAkB;AAC9B,aAAO;AAAA,IACT;AACA,UAAM,MAAM,iBAAiB,OAAO,MAAM,SAAS,IAAI;AACvD,QAAI,CAAC,KAAK;AACR,cAAQ,MAAM,mBAAmB,IAAI,qCAAqC,cAAc,MAAM,OAAO,CAAC,GAAG;AACzG,aAAO;AAAA,IACT;AACA,YAAQ,IAAI,KAAK,IAAI,MAAM,MAAM,GAAG,EAAE,CAAC,MAAM,IAAI,IAAI,MAAM,GAAG,EAAE,CAAC,MAAM,IAAI,MAAM,GAAG;AACpF,YAAQ,IAAI,IAAI,IAAI;AACpB,WAAO;AAAA,EACT;AACA,UAAQ,MAAM,8BAA8B,GAAG,EAAE;AACjD,SAAO;AACT;AAEA,eAAe,SAAS,GAA4B;AAClD,QAAM,EAAE,OAAO,QAAQ,KAAK,MAAM,YAAY,IAAI;AAClD,MAAI,QAAQ,WAAW;AACrB,YAAQ,MAAM,iCAAiC;AAC/C,WAAO;AAAA,EACT;AACA,QAAM,MAAM,KAAK,SAAS,WAAW;AACrC,QAAM,WAAWC,MAAK,KAAK,MAAM,SAAS,gBAAgB;AAC1D,QAAM,OAAO,OAAO,UAAU,gBAAgB;AAC9C,QAAM,OAAO,OAAO,UAAU,kBAAkB;AAChD,MAAI,KAAK;AACP,YAAQ,IAAI,yBAAyB,QAAQ,OAAO,OAAO,UAAU,aAAa,SACxE,WAAW,OAAO,OAAO,UAAU,eAAe,GAAG;AAC/D,WAAO;AAAA,EACT;AACA,QAAM,IAAI,eAAe,UAAU,IAAI;AACvC,QAAM,IAAI,eAAe,aAAa,IAAI;AAC1C,kBAAgB,aAAa,EAAE,OAAO,aAAa,iBAAiB,GAAG,iBAAiB,EAAE,CAAC;AAC3F,UAAQ,IAAI,mBAAmB,CAAC,aAAa,CAAC,EAAE;AAChD,SAAO;AACT;AAEA,eAAe,WAAW,GAA4B;AACpD,QAAM,EAAE,OAAO,OAAO,QAAQ,KAAK,KAAK,IAAI;AAC5C,UAAQ,KAAK;AAAA,IACX,KAAK,UAAU;AACb,YAAM,KAAK,aAAa,OAAO,KAAK;AACpC,YAAM,YAAY,cAAc,KAAK;AACrC,cAAQ,IAAI,KAAK,UAAU;AAAA,QACzB,cAAc,GAAG,OAAO,iBAAiB,IAAI,KAAK,GAAG,OAAO,cAAc,EAAE,YAAY,IAAI;AAAA,QAC5F,YAAY,GAAG,OAAO;AAAA,QACtB,eAAe,UAAU,WAAW,UAAU;AAAA,MAChD,GAAG,MAAM,CAAC,CAAC;AACX,aAAO;AAAA,IACT;AAAA,IACA,KAAK,OAAO;AACV,YAAM,SAAS,oBAAI,KAAK;AACxB,aAAO,SAAS,IAAI,GAAG,GAAG,CAAC;AAC3B,YAAM,SAAS,aAAa,OAAO,OAAO,QAAQ,MAAM;AACxD,cAAQ,IAAI,KAAK,UAAU,QAAQ,MAAM,CAAC,CAAC;AAC3C,aAAO;AAAA,IACT;AAAA,IACA,KAAK,QAAQ;AACX,YAAM,QAAQ,KAAK,KAAK,GAAG,EAAE,KAAK;AAClC,UAAI,CAAC,OAAO;AACV,gBAAQ,MAAM,4BAA4B;AAC1C,eAAO;AAAA,MACT;AACA,YAAM,IAAI,eAAe,OAAO,OAAO,KAAK;AAC5C,cAAQ,IAAI,KAAK,UAAU,CAAC,CAAC;AAC7B,aAAO;AAAA,IACT;AAAA,IACA;AACE,cAAQ,MAAM,8BAA8B,GAAG,EAAE;AACjD,aAAO;AAAA,EACX;AACF;AAEA,eAAe,WAAW,GAA4B;AACpD,QAAM,EAAE,OAAO,IAAI,IAAI;AACvB,UAAQ,KAAK;AAAA,IACX,KAAK;AACH,cAAQ,IAAI,MAAM,iBAAiB,KAAK,IAAI,oBAAoB,gBAAgB;AAChF,aAAO;AAAA,IACT,KAAK;AACH,YAAM,iBAAiB,KAAK;AAC5B,cAAQ,IAAI,oBAAoB;AAChC,aAAO;AAAA,IACT,KAAK;AACH,cAAQ,IAAI,MAAM,mBAAmB,KAAK,IAAI,SAAS,QAAQ;AAC/D,aAAO;AAAA,IACT;AACE,cAAQ,MAAM,mCAAmC;AACjD,aAAO;AAAA,EACX;AACF;AAEA,eAAe,YAAY,GAA4B;AACrD,QAAM,EAAE,OAAO,OAAO,KAAK,KAAK,IAAI;AACpC,QAAM,MAAM,YAAY,OAAO,gBAAgB,MAAM,OAAO,CAAC;AAC7D,QAAM,MAAM,KAAK,SAAS,OAAO;AACjC,UAAQ,KAAK;AAAA,IACX,KAAK,QAAQ;AACX,UAAI,IAAI;AACR,iBAAW,KAAK,CAAC,YAAY,YAAY,QAAQ,KAAK,GAAY;AAChE,mBAAW,KAAK,IAAI,WAAW,CAAC,EAAG,SAAS;AAC1C,cAAI,CAAC,OAAO,EAAE,YAAY,KAAM;AAChC,eAAK;AACL,kBAAQ,IAAI,GAAG,EAAE,EAAE,KAAK,EAAE,SAAS,IAAI,EAAE,KAAK,IAAI,EAAE,QAAQ,KAAK,EAAE,QAAQ,SAChE,EAAE,WAAW,QAAQ,CAAC,CAAC,GAAG,EAAE,cAAc,8BAAU,EAAE,GAAG,EAAE,UAAU,oBAAU,EAAE,KAAK,EAAE,QAAQ,MAAM,GAAG,EAAE,CAAC,EAAE;AAAA,QAC3H;AAAA,MACF;AACA,UAAI,MAAM,EAAG,SAAQ,IAAI,SAAS;AAClC,aAAO;AAAA,IACT;AAAA,IACA,KAAK,UAAU;AACb,YAAM,QAAQ,CAAC,+BAAU,oBAAI,KAAK,GAAE,YAAY,CAAC,IAAI,EAAE;AACvD,iBAAW,KAAK,CAAC,YAAY,YAAY,QAAQ,KAAK,GAAY;AAChE,cAAM,KAAK,MAAM,CAAC,EAAE;AACpB,mBAAW,KAAK,IAAI,WAAW,CAAC,EAAG,SAAS;AAC1C,cAAI,EAAE,YAAY,KAAM;AACxB,gBAAM,KAAK,MAAM,EAAE,KAAK,IAAI,EAAE,QAAQ,KAAK,EAAE,OAAO,UAAU,EAAE,WAAW,QAAQ,CAAC,CAAC,KAAK,EAAE,QAAQ,GAAG;AAAA,QACzG;AAAA,MACF;AACA,YAAM,MAAMA,MAAK,KAAK,MAAM,YAAY,kBAAkB,KAAK,IAAI,CAAC,KAAK;AACzE,gBAAU,OAAO,KAAK,MAAM,KAAK,IAAI,IAAI,IAAI;AAC7C,cAAQ,IAAI,aAAa,GAAG,EAAE;AAC9B,aAAO;AAAA,IACT;AAAA,IACA,KAAK,UAAU;AACb,YAAM,IAAI,cAAc,OAAO,MAAM,OAAO;AAC5C,cAAQ,IAAI,KAAK,UAAU,GAAG,MAAM,CAAC,CAAC;AACtC,aAAO,EAAE,KAAK,IAAI;AAAA,IACpB;AAAA,IACA,KAAK,WAAW;AACd,YAAM,IAAI,eAAe,OAAO,MAAM,SAAS,EAAE,OAAO,KAAK,SAAS,SAAS,EAAE,CAAC;AAClF,cAAQ,IAAI,KAAK,UAAU,GAAG,MAAM,CAAC,CAAC;AACtC,aAAO,EAAE,KAAK,IAAI;AAAA,IACpB;AAAA,IACA,KAAK,QAAQ;AACX,UAAI,CAAC,KAAK,SAAS,OAAO,GAAG;AAC3B,gBAAQ,IAAI,sEAAsE;AAClF,eAAO;AAAA,MACT;AACA,iBAAW,KAAK,CAAC,gBAAgB,uBAAuB,uBAAuB,GAAG;AAChF,cAAM,MAAM,MAAM,OAAOA,MAAK,KAAK,MAAM,SAAS,CAAC,CAAC;AACpD,YAAID,IAAG,WAAW,GAAG,EAAG,CAAAA,IAAG,OAAO,KAAK,EAAE,OAAO,KAAK,CAAC;AAAA,MACxD;AACA,cAAQ,IAAI,yDAAyD;AACrE,aAAO;AAAA,IACT;AAAA,IACA,KAAK,YAAY;AACf,YAAM,EAAE,aAAa,iBAAiB,mBAAmB,IAAI,MAAM,OAAO,yBAAwB;AAClG,YAAM,EAAE,QAAQ,MAAM,IAAI,YAAY,OAAO,MAAM,OAAO;AAC1D,cAAQ,IAAI,WAAW,KAAK,6BAAS,kBAAkB,QAAG;AAC1D,UAAI,CAAC,UAAU,CAAC,KAAK,SAAS,SAAS,GAAG;AACxC,gBAAQ,IAAI,2GAA2B;AACvC,eAAO;AAAA,MACT;AACA,YAAM,SAAS,gBAAgB,OAAO,MAAM,OAAO;AACnD,UAAI,CAAC,OAAO,IAAI;AACd,gBAAQ,IAAI,2BAAO,OAAO,MAAM,EAAE;AAClC,eAAO;AAAA,MACT;AACA,cAAQ,IAAI,sBAAO,OAAO,MAAM,6CAAoB,OAAO,UAAU,4BAAQ,OAAO,WAAW,6CAAoB;AACnH,cAAQ,IAAI,uHAAkC;AAC9C,aAAO;AAAA,IACT;AAAA,IACA;AACE,cAAQ,MAAM,+BAA+B,GAAG,EAAE;AAClD,aAAO;AAAA,EACX;AACF;AAEA,eAAe,SAAS,GAA4B;AAClD,QAAM,EAAE,OAAO,OAAO,KAAK,IAAI;AAC/B,QAAM,MAAM,KAAK,SAAS,OAAO;AACjC,QAAM,MAAM,KAAK,SAAS,OAAO;AACjC,QAAM,OAAO,SAAS,OAAO,OAAO,GAAG;AACvC,UAAQ,IAAI,mDAAW;AACvB,aAAW,KAAK,KAAM,SAAQ,IAAI,MAAM,EAAE,SAAS,iBAAO,UAAK,KAAK,EAAE,OAAO,QAAQ,EAAE,OAAO,GAAG,KAAK,EAAE,OAAO,IAAI,EAAE;AACrH,MAAI,CAAC,KAAK;AACR,YAAQ,IAAI,2HAAsC,MAAM,gDAAkB,0CAAY,QAAG;AACzF,WAAO;AAAA,EACT;AACA,QAAM,SAAS,YAAY,OAAO,OAAO,EAAE,IAAI,CAAC;AAChD,UAAQ,IAAI,WAAW,OAAO,OAAO,MAAM,yBAAe,OAAO,QAAQ,MAAM,SAAI;AACnF,SAAO;AACT;AAEA,eAAe,YAAY,GAA4B;AACrD,QAAM,EAAE,OAAO,OAAO,KAAK,KAAK,IAAI;AACpC,MAAI,QAAQ,UAAU;AACpB,UAAM,aAAaC,MAAK,KAAK,MAAM,YAAY,qBAAoB,oBAAI,KAAK,GAAE,YAAY,EAAE,MAAM,GAAG,EAAE,CAAC,QAAQ;AAChH,UAAM,UAAU,KAAK,CAAC,KAAK;AAC3B,QAAI;AACJ,QAAI;AACF,iBAAW,MAAM,OAAO,OAAO;AAAA,IACjC,QAAQ;AACN,cAAQ,MAAM,8IAAgC,OAAO;AAAA,gCAAU,UAAU,EAAE;AAC3E,aAAO;AAAA,IACT;AACA,UAAM,CAAC,KAAK,GAAG,IAAI,MAAM,UAAU,CAAC,oFAAmB,8CAAW,CAAC;AACnE,QAAI,CAAC,OAAO,QAAQ,KAAK;AACvB,cAAQ,MAAM,4FAAiB;AAC/B,aAAO;AAAA,IACT;AACA,UAAM,EAAE,SAAS,SAAS,IAAI,wBAAwB,OAAO,KAAK;AAClE,QAAI,QAAQ,WAAW,GAAG;AACxB,cAAQ,IAAI,wGAAwB;AACpC,aAAO;AAAA,IACT;AACA,IAAAD,IAAG,UAAUC,MAAK,QAAQ,QAAQ,GAAG,EAAE,WAAW,KAAK,CAAC;AACxD,wBAAoB,UAAU,iBAAiB,SAAS,GAAG,CAAC;AAC5D,YAAQ,IAAI,sBAAO,QAAQ,MAAM,8BAAU,QAAQ,EAAE;AACrD,YAAQ,IAAI,uBAAQ,SAAS,OAAO,KAAK,IAAI,CAAC,EAAE;AAChD,QAAI,SAAS,QAAQ,SAAS,EAAG,SAAQ,IAAI,qDAAa,SAAS,QAAQ,KAAK,IAAI,CAAC,EAAE;AACvF,YAAQ,IAAI,8MAAyC;AACrD,WAAO;AAAA,EACT;AACA,MAAI,QAAQ,UAAU;AACpB,UAAM,SAAS,KAAK,CAAC;AACrB,QAAI,CAAC,QAAQ;AACX,cAAQ,MAAM,wCAAwC;AACtD,aAAO;AAAA,IACT;AACA,UAAM,CAAC,EAAE,IAAI,MAAM,UAAU,CAAC,8CAAW,CAAC;AAC1C,QAAI;AACJ,QAAI;AACF,aAAOD,IAAG,aAAa,QAAQ,MAAM;AAAA,IACvC,QAAQ;AACN,cAAQ,MAAM,6CAAU,MAAM,EAAE;AAChC,aAAO;AAAA,IACT;AACA,QAAI;AACJ,QAAI;AACF,cAAQ,iBAAiB,MAAM,MAAM,EAAE;AAAA,IACzC,SAAS,GAAG;AACV,cAAQ,MAAM,OAAO,aAAa,QAAQ,EAAE,UAAU,CAAC,CAAC;AACxD,aAAO;AAAA,IACT;AACA,UAAM,SAAS,sBAAsB,OAAO,OAAO,MAAM,KAAK;AAC9D,YAAQ,IAAI,gBAAM,OAAO,SAAS,MAAM,yCAAW,OAAO,SAAS,MAAM,2DAAc,OAAO,QAAQ,MAAM,eAAK;AACjH,eAAW,KAAK,OAAO,SAAU,SAAQ,IAAI,mBAAS,CAAC,EAAE;AACzD,eAAW,KAAK,OAAO,SAAU,SAAQ,IAAI,mBAAS,CAAC,gBAAgB;AACvE,QAAI,OAAO,QAAQ,SAAS,EAAG,SAAQ,IAAI,mBAAS,OAAO,QAAQ,KAAK,IAAI,CAAC,EAAE;AAC/E,QAAI,OAAO,MAAO,SAAQ,IAAI,+CAAY,OAAO,KAAK,EAAE;AACxD,YAAQ,IAAI,2CAAa;AACzB,WAAO,OAAO,QAAQ,IAAI;AAAA,EAC5B;AACA,UAAQ,MAAM,+BAA+B,GAAG,EAAE;AAClD,SAAO;AACT;AAEA,eAAe,aAAa,GAA4B;AACtD,QAAM,EAAE,OAAO,MAAM,IAAI;AAGzB,QAAM,OAAOC,MAAK,KAAK,GAAG,QAAQ,GAAG,QAAQ,UAAU;AACvD,MAAI,QAAQ;AACZ,MAAID,IAAG,WAAW,IAAI,GAAG;AACvB,UAAM,EAAE,cAAc,IAAI,MAAM,OAAO,6BAAyB;AAChE,UAAM,MAAM,cAAc,OAAO,KAAK;AACtC,eAAW,QAAQA,IAAG,YAAY,IAAI,GAAG;AACvC,iBAAW,MAAMA,IAAG,YAAYC,MAAK,KAAK,MAAM,IAAI,CAAC,GAAG;AACtD,iBAAS;AACT,cAAM,OAAO,OAAO,MAAM,sCAAa;AACvC,gBAAQ,IAAI,GAAG,EAAE,MAAM,IAAI,IAAI,IAAI,EAAE;AAAA,MACvC;AAAA,IACF;AAAA,EACF;AACA,MAAI,UAAU,EAAG,SAAQ,IAAI,+BAA+B;AAC5D,SAAO;AACT;AAEA,eAAe,SAAS,GAA4B;AAClD,QAAM,EAAE,OAAO,OAAO,KAAK,KAAK,IAAI;AACpC,QAAM,EAAE,cAAc,YAAY,cAAc,IAAI,MAAM,OAAO,yBAAqB;AACtF,UAAQ,KAAK;AAAA,IACX,KAAK,QAAQ;AACX,YAAM,OAAO,aAAa,OAAO,MAAM,WAAW;AAClD,YAAM,EAAE,cAAc,IAAI,MAAM,OAAO,6BAAyB;AAChE,YAAM,MAAM,cAAc,OAAO,KAAK;AACtC,UAAI,IAAK,SAAQ,IAAI,6BAAS,GAAG,2GAAgC;AACjE,iBAAW,KAAK,KAAK,UAAU;AAC7B,gBAAQ,IAAI,GAAG,EAAE,SAAS,aAAa,EAAE,UAAU,WAAM,MAAG,YAAY,EAAE,UAAU,WAAM,MAAG,EAAE;AAAA,MACjG;AACA,UAAI,KAAK,SAAS,WAAW,KAAK,CAAC,IAAK,SAAQ,IAAI,0EAAqE;AACzH,aAAO;AAAA,IACT;AAAA,IACA,KAAK,OAAO;AACV,YAAM,KAAK,KAAK,CAAC;AACjB,UAAI,CAAC,MAAM,CAAC,GAAG,WAAW,UAAU,GAAG;AACrC,gBAAQ,MAAM,8EAA8E;AAC5F,eAAO;AAAA,MACT;AACA,YAAM,UAAU,KAAK,SAAS,WAAW,KAAK,KAAK,SAAS,gBAAgB;AAC5E,YAAM,UAAU,CAAC,KAAK,SAAS,cAAc,KAAK,CAAC,KAAK,SAAS,gBAAgB;AACjF,YAAM,IAAI,WAAW,OAAO,MAAM,aAAa,IAAI,EAAE,SAAS,QAAQ,CAAC;AACvE,cAAQ,IAAI,SAAS,EAAE,SAAS,YAAY,EAAE,OAAO,YAAY,EAAE,OAAO,EAAE;AAC5E,aAAO;AAAA,IACT;AAAA,IACA,KAAK,UAAU;AACb,YAAM,KAAK,KAAK,CAAC;AACjB,UAAI,CAAC,IAAI;AACP,gBAAQ,MAAM,gCAAgC;AAC9C,eAAO;AAAA,MACT;AACA,cAAQ,IAAI,cAAc,OAAO,MAAM,aAAa,EAAE,IAAI,WAAW,EAAE,KAAK,WAAW;AAKvF,YAAM,EAAE,iBAAiB,IAAI,MAAM,OAAO,6BAAyB;AACnE,UAAI,iBAAiB,OAAO,OAAO,EAAE,GAAG;AACtC,gBAAQ,IAAI,kPAA0C;AAAA,MACxD;AACA,aAAO;AAAA,IACT;AAAA,IACA;AACE,cAAQ,MAAM,yDAAyD;AACvE,aAAO;AAAA,EACX;AACF;AAEA,eAAe,WAAW,GAA4B;AACpD,QAAM,EAAE,KAAK,MAAM,KAAK,IAAI;AAC5B,QAAM,KAAK,KAAK,MAAM,MAAM,KAAK;AAGjC,QAAM,OAAO,2BAA2B;AACxC,QAAM,SAAS,aAAa,YAAY,KAAK,IAAI,IAAI;AACrD,MAAI,QAAQ,UAAa,QAAQ,UAAU;AACzC,YAAQ,IAAI,iBAAiB,OAAO,EAAE,EAAE;AACxC,YAAQ,IAAI,iBAAiB,OAAO,YAAY,QAAQ,IAAI,EAAE;AAC9D,YAAQ,IAAI,iBAAiB,OAAO,GAAG,EAAE;AACzC,YAAQ,IAAI,iBAAiB,OAAO,cAAc,gCAAgC,EAAE;AACpF,QAAI,OAAO,WAAW;AACpB,cAAQ;AAAA,QACN,iBAAiB,OAAO,qBAAqB,iCAAiC,sEAAsE;AAAA,MACtJ;AAAA,IACF;AACA,QAAI,CAAC,OAAO,WAAW;AACrB,cAAQ,IAAI,4FAA4F;AACxG,cAAQ,IAAI,oCAAoC;AAAA,IAClD;AACA,WAAO,OAAO,YAAY,IAAI;AAAA,EAChC;AACA,MAAI,QAAQ,WAAW;AACrB,UAAM,SAAS,qBAAqB;AAAA,MAClC,WAAW,YAAY;AAAA,MACvB;AAAA,MACA;AAAA,MACA,OAAO,KAAK,SAAS,SAAS;AAAA,IAChC,CAAC;AACD,YAAQ,IAAI,gBAAgB,MAAM,CAAC;AACnC,WAAO,OAAO,WAAW,UAAU,IAAI;AAAA,EACzC;AACA,UAAQ,MAAM,4DAA4D;AAC1E,SAAO;AACT;AAGA,IAAM,QAA8B;AAAA,EAClC,QAAQ;AAAA,EACR,OAAO;AAAA,EACP,QAAQ;AAAA,EACR,QAAQ;AAAA,EACR,MAAM;AAAA,EACN,QAAQ;AAAA,EACR,QAAQ;AAAA,EACR,SAAS;AAAA,EACT,MAAM;AAAA,EACN,SAAS;AAAA,EACT,UAAU;AAAA,EACV,MAAM;AAAA,EACN,QAAQ;AACV;AAEA,eAAsB,KAAK,MAAiC;AAC1D,QAAM,CAAC,KAAK,KAAK,GAAG,IAAI,IAAI;AAC5B,MAAI,CAAC,OAAO,QAAQ,UAAU,QAAQ,UAAU;AAC9C,YAAQ,IAAI,MAAM,CAAC;AACnB,WAAO;AAAA,EACT;AACA,QAAM,OAAO,MAAM,GAAG;AACtB,MAAI,CAAC,MAAM;AACT,YAAQ,MAAM,oBAAoB,GAAG,EAAE;AACvC,YAAQ,IAAI,MAAM,CAAC;AACnB,WAAO;AAAA,EACT;AACA,QAAM,QAAQ,cAAc;AAC5B,QAAM,QAAQ,gBAAgB,MAAM,OAAO;AAC3C,QAAM,SAAS,WAAW,OAAO,MAAM,WAAW,MAAM,WAAW;AACnE,QAAM,cAAcA,MAAK,KAAK,MAAM,SAAS,iBAAiB;AAE9D,QAAM,YAAY,CAAC,UAAyC;AAC1D,QAAI;AACF,sBAAgB,aAAa,KAAK;AAAA,IACpC,QAAQ;AAAA,IAA2C;AAAA,EACrD;AACA,SAAO,KAAK;AAAA,IACV;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,WAAW,cAAc,MAAM,OAAO;AAAA,IACtC,YAAY,eAAe,MAAM,OAAO;AAAA,IACxC;AAAA,IACA;AAAA,EACF,CAAC;AACH;AAEA,IAAI,QAAQ,KAAK,CAAC,KAAK,YAAY,QAAQ,IAAI,IAAI,WAAW,QAAQ,KAAK,CAAC,EAAE,QAAQ,OAAO,GAAG,CAAC,EAAE,EAAE,MAAM;AAEzG,OAAK,KAAK,QAAQ,KAAK,MAAM,CAAC,CAAC,EAC5B,KAAK,CAAC,SAAS;AAAE,YAAQ,WAAW;AAAA,EAAM,CAAC,EAC3C,MAAM,CAAC,MAAe;AAErB,YAAQ,MAAM,CAAC;AACf,YAAQ,WAAW;AAAA,EACrB,CAAC;AACL;","names":["fs","path","fs","path"]}
@@ -7,9 +7,9 @@ import {
7
7
  inboxFileExists,
8
8
  inboxFilePath,
9
9
  inboxHealthCheck
10
- } from "./chunk-BQCXYE7N.js";
10
+ } from "./chunk-3MDBU6WY.js";
11
11
  import "./chunk-IV2ZWQA3.js";
12
- import "./chunk-7TW6DD6Q.js";
12
+ import "./chunk-K5Y6JP2B.js";
13
13
  import "./chunk-WRUTATW4.js";
14
14
  export {
15
15
  dedupeItems,
@@ -21,4 +21,4 @@ export {
21
21
  inboxFilePath,
22
22
  inboxHealthCheck
23
23
  };
24
- //# sourceMappingURL=inbox-JLT5G7TL.js.map
24
+ //# sourceMappingURL=inbox-P26DDMWC.js.map
package/dist/index.d.ts CHANGED
@@ -350,6 +350,8 @@ interface Policy {
350
350
  };
351
351
  weekly: {
352
352
  enabled: boolean;
353
+ /** v2.0 (item 5): how many past reports the store keeps and the card lists. */
354
+ keepReports: number;
353
355
  };
354
356
  retention: {
355
357
  envPulseHours: number;
@@ -368,6 +370,29 @@ interface PathGuard {
368
370
  check(target: string): string | null;
369
371
  }
370
372
 
373
+ type RelocateResult = {
374
+ action: 'relocated';
375
+ /** Package-local tree the data came from (now deleted). */
376
+ srcDir: string;
377
+ dstDir: string;
378
+ backupDir: string;
379
+ files: number;
380
+ bytes: number;
381
+ /** Plaintext JSON/JSONL that does not parse (verified byte-identical). */
382
+ warnings: string[];
383
+ /** Paths that could not be deleted after the move (cosmetic leftovers). */
384
+ leftovers: string[];
385
+ } | {
386
+ action: 'skipped';
387
+ reason: 'source-missing' | 'no-payload' | 'destination-exists';
388
+ } | {
389
+ action: 'failed';
390
+ stage: 'backup' | 'copy' | 'verify' | 'commit';
391
+ problems: string[];
392
+ /** Null when the backup itself could not be created. */
393
+ backupDir: string | null;
394
+ };
395
+
371
396
  interface WorkspacePaths {
372
397
  /** Guard boundary and the only writable tree at runtime. */
373
398
  dataDir: string;
@@ -379,6 +404,11 @@ interface WorkspacePaths {
379
404
  packageRoot: string;
380
405
  configDir: string;
381
406
  assetsDir: string;
407
+ /**
408
+ * Set only when a legacy package-local data dir was found: the outcome of
409
+ * the one-time relocation. Absent for explicit dirs and fresh installs.
410
+ */
411
+ relocation?: RelocateResult;
382
412
  }
383
413
 
384
414
  interface OrchestratorDeps {
@@ -403,6 +433,11 @@ interface OrchestratorDeps {
403
433
  policy: Policy;
404
434
  /** Agent preset the heartbeat agent joins (composition entry `agentPreset`). */
405
435
  agentPreset?: string;
436
+ /** Awaited right before the preset mount: the plugin registers its preset at
437
+ * runtime (issue #2 — the composition must not name a host package), and the
438
+ * mount must not race that registration. Resolves at once when registration
439
+ * was skipped or the host has no registry API. */
440
+ presetRegistration?: () => Promise<void>;
406
441
  /** Extra tool names the engine-room allow-list should include (config
407
442
  * `extraTools`, comma-separated in the composition entry). Only names that
408
443
  * actually exist in the global layer are applied. */
package/dist/index.js CHANGED
@@ -6,7 +6,7 @@ import {
6
6
  loadPolicy,
7
7
  updateUserPolicy,
8
8
  userPresetRoot
9
- } from "./chunk-ZLV4NMFX.js";
9
+ } from "./chunk-XYYEJK3W.js";
10
10
  import {
11
11
  addBinding,
12
12
  loadBindings,
@@ -27,7 +27,7 @@ import {
27
27
  sessionEventCount,
28
28
  sessionEvents,
29
29
  startOrchestrator
30
- } from "./chunk-HT57FOEF.js";
30
+ } from "./chunk-TRO4E6WG.js";
31
31
  import {
32
32
  appendEntry,
33
33
  ledgerFilePath,
@@ -36,7 +36,7 @@ import {
36
36
  readLedger,
37
37
  readWeeklyReport,
38
38
  scanPending
39
- } from "./chunk-WRJCINZ7.js";
39
+ } from "./chunk-WLZSABBH.js";
40
40
  import {
41
41
  getRuntime,
42
42
  setRuntime
@@ -49,25 +49,25 @@ import {
49
49
  loadPool,
50
50
  restoreSeed,
51
51
  seedsFilePath
52
- } from "./chunk-KOOQOMQY.js";
53
- import "./chunk-BQCXYE7N.js";
52
+ } from "./chunk-JDH2LDFS.js";
53
+ import "./chunk-3MDBU6WY.js";
54
54
  import "./chunk-IV2ZWQA3.js";
55
- import "./chunk-QOQ7EPZZ.js";
55
+ import "./chunk-KB5SMG3F.js";
56
56
  import {
57
57
  appendAuditLine,
58
58
  loadProfile,
59
59
  profileFilePath
60
- } from "./chunk-OYVNWB5G.js";
60
+ } from "./chunk-CUOSICYJ.js";
61
61
  import {
62
62
  initWorkspace,
63
63
  writeText
64
- } from "./chunk-7TW6DD6Q.js";
64
+ } from "./chunk-K5Y6JP2B.js";
65
65
  import {
66
66
  atomicWriteFileSync,
67
67
  atomicWriteJsonSync
68
68
  } from "./chunk-WRUTATW4.js";
69
69
 
70
- // node_modules/@deepseek-ai/cosmokit/lib/index.js
70
+ // node_modules/.pnpm/@deepseek-ai+cosmokit@1.8.5/node_modules/@deepseek-ai/cosmokit/lib/index.js
71
71
  function isNullable(value) {
72
72
  return value === null || value === void 0;
73
73
  }
@@ -292,7 +292,7 @@ var Time;
292
292
  Time2.template = template;
293
293
  })(Time || (Time = {}));
294
294
 
295
- // node_modules/@deepseek-ai/schemastery/lib/index.mjs
295
+ // node_modules/.pnpm/@deepseek-ai+schemastery@3.18.4/node_modules/@deepseek-ai/schemastery/lib/index.mjs
296
296
  var kSchema = /* @__PURE__ */ Symbol.for("schemastery");
297
297
  var kValidationError = /* @__PURE__ */ Symbol.for("ValidationError");
298
298
  globalThis.__schemastery_index__ ??= 0;
@@ -1450,9 +1450,36 @@ function buildEndpoints(deps, isLive) {
1450
1450
  tact: d.tact,
1451
1451
  topic: d.topic,
1452
1452
  wander: d.wander,
1453
- withinBudget: d.withinBudget
1453
+ withinBudget: d.withinBudget,
1454
+ // v2.0 (item 6): the card shows the budget and what the caps dropped.
1455
+ totalChars: d.totalChars,
1456
+ budgetChars: d.budgetChars,
1457
+ omitted: d.omitted
1454
1458
  });
1455
1459
  },
1460
+ "profile.partitions"() {
1461
+ const doc = loadProfile(guard, profileFilePath(paths.dataDir));
1462
+ const partitions = {};
1463
+ for (const part of ["interest", "projects", "comm", "psy"]) {
1464
+ const all = doc.partitions[part]?.entries ?? [];
1465
+ const valid = all.filter((e) => e.validTo === null);
1466
+ partitions[part] = {
1467
+ total: all.length,
1468
+ valid: valid.length,
1469
+ entries: valid.slice().sort((a, b) => b.confidence - a.confidence || (a.updatedAt < b.updatedAt ? 1 : -1)).map((e) => ({
1470
+ id: e.id,
1471
+ topic: e.topic,
1472
+ subTopic: e.subTopic,
1473
+ content: e.content,
1474
+ confidence: e.confidence,
1475
+ temporal: e.temporal,
1476
+ updatedAt: e.updatedAt,
1477
+ lowActivity: e.lowActivity === true
1478
+ }))
1479
+ };
1480
+ }
1481
+ return ok({ partitions });
1482
+ },
1456
1483
  "profile.export"() {
1457
1484
  const doc = loadProfile(guard, profileFilePath(paths.dataDir));
1458
1485
  const lines = [`# \u753B\u50CF\u5BFC\u51FA ${(/* @__PURE__ */ new Date()).toISOString()}`, ""];
@@ -1473,7 +1500,7 @@ function buildEndpoints(deps, isLive) {
1473
1500
  spawn("cmd", ["/c", "start", "", f], { detached: true, stdio: "ignore" }).unref();
1474
1501
  return ok({ path: f });
1475
1502
  },
1476
- "weekly.list": () => ok({ reports: listWeeklyReports(guard, paths.dataDir) }),
1503
+ "weekly.list": () => ok({ reports: listWeeklyReports(guard, paths.dataDir, policy.weekly.keepReports) }),
1477
1504
  "weekly.get"(p) {
1478
1505
  const file = String(p.file ?? "");
1479
1506
  const rep = readWeeklyReport(guard, paths.dataDir, file);
@@ -1483,7 +1510,7 @@ function buildEndpoints(deps, isLive) {
1483
1510
  async "migrate.export"(p) {
1484
1511
  const passphrase = String(p.passphrase ?? "");
1485
1512
  if (!passphrase) return err("bad-request", "\u9700\u8981\u8BBE\u7F6E\u53E3\u4EE4");
1486
- const { collectMigrationEntries, encryptContainer } = await import("./migrate-WDVFHUP7.js");
1513
+ const { collectMigrationEntries, encryptContainer } = await import("./migrate-D4VKAKYT.js");
1487
1514
  const { entries } = collectMigrationEntries(guard, paths);
1488
1515
  if (entries.length === 0) return err("bad-request", "\u6CA1\u6709\u53EF\u6253\u5305\u7684\u8BB0\u5FC6\u6587\u4EF6\uFF08data/ \u662F\u7A7A\u7684\uFF09");
1489
1516
  const out = path4.join(paths.exportsDir, `heartbeat-memory-${(/* @__PURE__ */ new Date()).toISOString().slice(0, 10)}.hbmig`);
@@ -1495,7 +1522,7 @@ function buildEndpoints(deps, isLive) {
1495
1522
  const passphrase = String(p.passphrase ?? "");
1496
1523
  const file = String(p.file ?? "");
1497
1524
  if (!passphrase || !file) return err("bad-request", "\u9700\u8981\u5BB9\u5668\u8DEF\u5F84\u4E0E\u53E3\u4EE4");
1498
- const { decryptContainer, applyMigrationEntries } = await import("./migrate-WDVFHUP7.js");
1525
+ const { decryptContainer, applyMigrationEntries } = await import("./migrate-D4VKAKYT.js");
1499
1526
  let text;
1500
1527
  try {
1501
1528
  text = fs4.readFileSync(file, "utf8");
@@ -1680,6 +1707,47 @@ function registerStatusbarSection(ctx, guard, paths, opts) {
1680
1707
  });
1681
1708
  }
1682
1709
 
1710
+ // src/core/preset-definition.ts
1711
+ function heartbeatPresetDefinition(id = "heartbeat") {
1712
+ return {
1713
+ id,
1714
+ name: "\u5FC3\u8DF3\u6A21\u5F0F",
1715
+ description: "\u5FC3\u8DF3 agent \u4E13\u7528\uFF1A\u4EC5 web_search + \u4E0A\u4E0B\u6587\u6298\u53E0\uFF1B\u65E0 shell\u3001\u65E0\u6587\u4EF6\u3001\u65E0\u5B50\u4EE3\u7406\u3002",
1716
+ order: 20,
1717
+ plugins: [
1718
+ {
1719
+ id: "compaction",
1720
+ name: "cordis:group",
1721
+ group: true,
1722
+ isolate: { compaction: true, toolResultPruner: true },
1723
+ config: [
1724
+ { id: "compaction-basic", name: "@deepseek-ai/dsh-compaction-basic" },
1725
+ { id: "command-compact", name: "@deepseek-ai/dsh-command-compact" },
1726
+ {
1727
+ id: "tool-result-pruner",
1728
+ name: "@deepseek-ai/dsh-compaction-tool-result-pruner",
1729
+ config: { thresholdChars: 8192, headChars: 4096, tailChars: 1024 }
1730
+ }
1731
+ ]
1732
+ },
1733
+ { id: "tool-web", name: "@deepseek-ai/dsh-tool-web", config: { fetch: false, searchTimeoutMs: 6e4 } }
1734
+ ]
1735
+ };
1736
+ }
1737
+ async function registerHeartbeatPreset(service, id = "heartbeat", enabled = true) {
1738
+ if (!enabled) return { action: "skipped-disabled", id };
1739
+ const registrar = service;
1740
+ if (registrar === void 0 || registrar === null || typeof registrar.register !== "function") {
1741
+ return { action: "skipped-no-api", id };
1742
+ }
1743
+ try {
1744
+ await registrar.register(heartbeatPresetDefinition(id));
1745
+ return { action: "registered", id };
1746
+ } catch (e) {
1747
+ return { action: "error", id, detail: String(e).slice(0, 200) };
1748
+ }
1749
+ }
1750
+
1683
1751
  // src/ledger/tool.ts
1684
1752
  var MAX_TEXT = 120;
1685
1753
  function clean(v) {
@@ -1774,7 +1842,7 @@ var Config = Schema.object({
1774
1842
  /** IANA timezone for the injected clock; empty = process zone. */
1775
1843
  timeZone: Schema.string().default(""),
1776
1844
  /** Statusbar master switch (D19). Off = no section/pre-step status; time injection unaffected. */
1777
- statusbar: Schema.boolean().default(true),
1845
+ statusbar: Schema.boolean().default(false),
1778
1846
  /** v1.6.3 闲着模式:素材池为空时用画像话题兜底主动搭话(默认关)。 */
1779
1847
  idleMode: Schema.boolean().default(false),
1780
1848
  /** v1.7.0 节省 token 模式:用户离开(闲置 ≥30 分钟)或锁屏时整跳暂停(默认关)。 */
@@ -1809,7 +1877,8 @@ function apply(ctx, config = {}) {
1809
1877
  guard,
1810
1878
  policy,
1811
1879
  agentPreset: config.agentPreset || "heartbeat",
1812
- extraTools: (config.extraTools ?? "").split(",").map((s) => s.trim()).filter(Boolean)
1880
+ extraTools: (config.extraTools ?? "").split(",").map((s) => s.trim()).filter(Boolean),
1881
+ presetRegistration: () => presetRegistration ?? Promise.resolve()
1813
1882
  };
1814
1883
  setRuntime({
1815
1884
  paths,
@@ -1822,23 +1891,36 @@ function apply(ctx, config = {}) {
1822
1891
  tokenSaver: () => tokenSaverRef
1823
1892
  }
1824
1893
  });
1894
+ let presetRegistration;
1825
1895
  ctx.inject(["agentPresets"], (presetCtx) => {
1826
1896
  const service = presetCtx.agentPresets;
1897
+ const presetId = config.agentPreset || "heartbeat";
1898
+ const installEnabled = config.installPreset !== false;
1899
+ const audit = (entry) => {
1900
+ try {
1901
+ appendAuditLine(guard.assert(paths.logsDir + "/heartbeat.jsonl"), entry);
1902
+ } catch (e) {
1903
+ ctx.logger.warn("heartbeat: preset audit failed (%s)", String(e).slice(0, 120));
1904
+ }
1905
+ };
1906
+ presetRegistration = registerHeartbeatPreset(service, presetId, installEnabled).then((result2) => {
1907
+ audit({ event: "preset_register", ...result2 });
1908
+ if (result2.action === "error") {
1909
+ ctx.logger.warn("heartbeat: preset register failed (%s) \u2014 the engine room runs without it", result2.detail ?? "");
1910
+ } else if (result2.action === "registered") {
1911
+ ctx.logger.info("heartbeat: preset %s registered at runtime", result2.id);
1912
+ } else {
1913
+ ctx.logger.info("heartbeat: preset registration skipped (%s)", result2.action);
1914
+ }
1915
+ });
1827
1916
  const root = userPresetRoot(service?.roots);
1828
1917
  const result = installBundledPreset({
1829
1918
  moduleUrl: import.meta.url,
1830
- id: config.agentPreset || "heartbeat",
1919
+ id: presetId,
1831
1920
  ...root === void 0 ? { rosterKnown: service !== void 0 } : { root },
1832
- enabled: config.installPreset !== false
1921
+ enabled: installEnabled
1833
1922
  });
1834
- try {
1835
- appendAuditLine(guard.assert(paths.logsDir + "/heartbeat.jsonl"), {
1836
- event: "preset_install",
1837
- ...result
1838
- });
1839
- } catch (e) {
1840
- ctx.logger.warn("heartbeat: preset_install audit failed (%s)", String(e).slice(0, 120));
1841
- }
1923
+ audit({ event: "preset_install", ...result });
1842
1924
  const line = describeInstall(result);
1843
1925
  if (result.action === "error" || result.action === "skipped-no-root") {
1844
1926
  ctx.logger.warn("heartbeat: %s", line);
@@ -1917,6 +1999,35 @@ function apply(ctx, config = {}) {
1917
1999
  guard.assert(paths.logsDir + "/heartbeat.jsonl"),
1918
2000
  { event: "plugin_init", dataDir: paths.dataDir }
1919
2001
  );
2002
+ if (paths.relocation) {
2003
+ const auditFile = guard.assert(paths.logsDir + "/heartbeat.jsonl");
2004
+ if (paths.relocation.action === "relocated") {
2005
+ appendAuditLine(auditFile, {
2006
+ event: "data_dir_relocated",
2007
+ from: paths.relocation.srcDir,
2008
+ to: paths.relocation.dstDir,
2009
+ files: paths.relocation.files,
2010
+ bytes: paths.relocation.bytes,
2011
+ warnings: paths.relocation.warnings,
2012
+ leftovers: paths.relocation.leftovers
2013
+ });
2014
+ ctx.logger.info(
2015
+ "heartbeat: data dir moved out of the package (%s files, %s bytes)",
2016
+ paths.relocation.files,
2017
+ paths.relocation.bytes
2018
+ );
2019
+ } else if (paths.relocation.action === "failed") {
2020
+ appendAuditLine(auditFile, {
2021
+ event: "data_dir_relocate_failed",
2022
+ stage: paths.relocation.stage,
2023
+ problems: paths.relocation.problems
2024
+ });
2025
+ ctx.logger.warn(
2026
+ "heartbeat: data dir relocation failed (%s); continuing in the package dir",
2027
+ paths.relocation.stage
2028
+ );
2029
+ }
2030
+ }
1920
2031
  const uiGet = () => ({
1921
2032
  intervalMin: getRuntime().policy.heartbeat.intervalMin,
1922
2033
  maxDailySend: getRuntime().policy.gate.maxDailySend,