@kanadego/dsh-heartbeat 1.7.4 → 1.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +52 -15
- package/client.js +93 -0
- package/config/policy.json +73 -64
- package/dist/{chunk-ON4MSU6E.js → chunk-2SYXKKZF.js} +286 -480
- package/dist/chunk-2SYXKKZF.js.map +1 -0
- package/dist/{chunk-4UE74TUB.js → chunk-63FUJLIF.js} +2 -2
- package/dist/{chunk-LLD7LUNN.js → chunk-IFTFDHZX.js} +2 -1
- package/dist/chunk-IPOZFZPY.js +177 -0
- package/dist/chunk-IPOZFZPY.js.map +1 -0
- package/dist/{chunk-SVP2NDRF.js → chunk-PQTSXW4F.js} +38 -9
- package/dist/chunk-PQTSXW4F.js.map +1 -0
- package/dist/chunk-RB3NLLGF.js +87 -0
- package/dist/chunk-RB3NLLGF.js.map +1 -0
- package/dist/chunk-VIZNIQLK.js +472 -0
- package/dist/chunk-VIZNIQLK.js.map +1 -0
- package/dist/cli/index.js +149 -15
- package/dist/cli/index.js.map +1 -1
- package/dist/{inbox-MMLHISQV.js → inbox-57NHQHY3.js} +3 -3
- package/dist/index.js +790 -209
- package/dist/index.js.map +1 -1
- package/dist/migrate-N6NXMZ3G.js +20 -0
- package/dist/{pool-YAIBE2L5.js → pool-7I4VACG2.js} +3 -3
- package/dist/pool-7I4VACG2.js.map +1 -0
- package/dist/snapshot-ZBCSX67Y.js +15 -0
- package/dist/snapshot-ZBCSX67Y.js.map +1 -0
- package/package.json +1 -1
- package/dist/chunk-ON4MSU6E.js.map +0 -1
- package/dist/chunk-SVP2NDRF.js.map +0 -1
- /package/dist/{chunk-4UE74TUB.js.map → chunk-63FUJLIF.js.map} +0 -0
- /package/dist/{chunk-LLD7LUNN.js.map → chunk-IFTFDHZX.js.map} +0 -0
- /package/dist/{inbox-MMLHISQV.js.map → inbox-57NHQHY3.js.map} +0 -0
- /package/dist/{pool-YAIBE2L5.js.map → migrate-N6NXMZ3G.js.map} +0 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/core/audit-log.ts","../src/core/atomic-fs.ts","../src/profile/store.ts","../src/profile/types.ts","../src/profile/schema.ts"],"sourcesContent":["// Append-only JSONL audit log with age-based retention pruning.\n// Audit files are plaintext by charter (transparency), and must never contain\n// sensitive raw observations (window titles, conversation text).\n\nimport fs from 'node:fs';\nimport path from 'node:path';\nimport { atomicWriteFileSync } from './atomic-fs.js';\n\nexport interface AuditEvent {\n ts: string;\n [key: string]: unknown;\n}\n\nexport function appendAuditLine(file: string, event: Omit<AuditEvent, 'ts'> & { ts?: string }): void {\n fs.mkdirSync(path.dirname(file), { recursive: true });\n const line = JSON.stringify({ ts: event.ts ?? new Date().toISOString(), ...event });\n fs.appendFileSync(file, line + '\\n', 'utf8');\n}\n\nexport function readAuditLines<T = AuditEvent>(file: string): T[] {\n if (!fs.existsSync(file)) return [];\n const out: T[] = [];\n const raw = fs.readFileSync(file, 'utf8');\n for (const line of raw.split('\\n')) {\n const trimmed = line.trim();\n if (!trimmed) continue;\n try {\n out.push(JSON.parse(trimmed) as T);\n } catch {\n // Skip corrupt lines; the log is diagnostic, not authoritative data.\n out.push({ ts: '', corrupt: true, raw: trimmed.slice(0, 200) } as unknown as T);\n }\n }\n return out;\n}\n\n/**\n * Drop entries older than maxAgeMs. Returns the number of removed lines.\n * Rewrites the file atomically; on rewrite failure the original is untouched.\n */\nexport function pruneAuditFile(file: string, maxAgeMs: number, now = Date.now()): number {\n if (!fs.existsSync(file)) return 0;\n const lines = readAuditLines(file);\n const kept = lines.filter((e) => {\n const ev = e as unknown as AuditEvent;\n const ts = Date.parse(ev.ts ?? '');\n if (!Number.isFinite(ts)) return true; // keep unparseable lines, never lose audit data silently\n return now - ts <= maxAgeMs;\n });\n const removed = lines.length - kept.length;\n if (removed === 0) return 0;\n const body = kept.map((e) => JSON.stringify(e)).join('\\n');\n atomicWriteFileSync(file, body ? body + '\\n' : '');\n return removed;\n}\n","// Crash-safe file replacement: write to a random-suffix temp file in the SAME\n// directory as the target, then rename over it. Same-directory rename stays\n// on one volume (atomic) and Node's rename replaces existing files on Windows.\n\nimport fs from 'node:fs';\nimport path from 'node:path';\nimport { randomUUID, randomFillSync } from 'node:crypto';\n\nexport function tmpSibling(target: string, tag = 'w'): string {\n return path.join(\n path.dirname(target),\n `.${path.basename(target)}.${tag}-${randomUUID().slice(0, 8)}.tmp`,\n );\n}\n\nexport function atomicWriteFileSync(target: string, data: string | Uint8Array): void {\n const tmp = tmpSibling(target);\n try {\n fs.writeFileSync(tmp, data);\n fs.renameSync(tmp, target);\n } finally {\n fs.rmSync(tmp, { force: true });\n }\n}\n\nexport function atomicWriteJsonSync(target: string, value: unknown): void {\n atomicWriteFileSync(target, JSON.stringify(value, null, 2));\n}\n\n/** Overwrite a file's bytes with random data before unlinking. */\nexport function shredFileSync(target: string, passes = 3): void {\n const stat = fs.statSync(target);\n if (!stat.isFile()) throw new Error(`shred: not a file: ${target}`);\n const buf = Buffer.alloc(Math.max(stat.size, 1));\n for (let i = 0; i < passes; i++) {\n randomFillSync(buf);\n fs.writeFileSync(target, buf);\n }\n fs.rmSync(target, { force: true });\n}\n","// Profile store: materialized view + journal (the journal is the ONLY\n// authority; profile.json is a pure projection - r2 §14 verify/rebuild).\n// Every LLM-proposed op passes deterministic guards here (LLM nominates,\n// code decides - §3.3).\n\nimport path from 'node:path';\nimport { randomUUID } from 'node:crypto';\nimport fs from 'node:fs';\nimport type { PathGuard } from '../core/path-guard.js';\nimport { loadJson, saveJson, readText, writeText } from '../vault/vault.js';\nimport { atomicWriteFileSync } from '../core/atomic-fs.js';\nimport type { Policy } from '../config/schema.js';\nimport {\n CONFIDENCE_CAP,\n emptyProfile,\n PARTITIONS,\n type ApplyReport,\n type Evidence,\n type EvidenceKind,\n type InboxItem,\n type JournalRecord,\n type Partition,\n type ProfileDoc,\n type ProfileEntry,\n type ProfileOp,\n} from './types.js';\nimport { checkAddAgainstSchema, type ProfileSchema } from './schema.js';\n\nconst DAY_MS = 86_400_000;\n\nexport function profileFilePath(dataDir: string): string {\n return path.join(dataDir, 'profile.json');\n}\n\nexport function journalFilePath(dataDir: string): string {\n return path.join(dataDir, 'profile_journal.jsonl');\n}\n\n// ── snapshot basepoint (v1.8.0, design doc §14 ③) ─────────────────────────\n// The journal grows forever; the snapshot folds its history into one DPAPI\n// document and moves the folded records into a timestamped archive shard.\n// Replay order: snapshot → archives (name order) → live journal, skipping\n// records at or before the snapshot baseline — so verify/rebuild stay correct\n// without knowing whether a snapshot exists.\n\nexport const SNAPSHOT_FILE = 'profile_snapshot.json';\nexport const ARCHIVE_PREFIX = 'profile_journal.archive-';\n\nexport interface ProfileSnapshot {\n version: 1;\n /** ts of the LAST journal record folded into `doc`. */\n baselineTs: string;\n recordsFolded: number;\n doc: ProfileDoc;\n}\n\nexport function snapshotFilePath(dataDir: string): string {\n return path.join(dataDir, SNAPSHOT_FILE);\n}\n\nfunction loadSnapshot(guard: PathGuard, dataDir: string): ProfileSnapshot | null {\n const snap = loadJson<ProfileSnapshot>(guard, snapshotFilePath(dataDir));\n if (!snap || snap.version !== 1 || typeof snap.baselineTs !== 'string' || !snap.doc?.partitions) return null;\n return snap;\n}\n\nfunction listArchiveFiles(guard: PathGuard, dataDir: string): string[] {\n try {\n return fs.readdirSync(guard.assert(dataDir))\n .filter((f) => f.startsWith(ARCHIVE_PREFIX) && f.endsWith('.jsonl'))\n .sort(); // timestamped names sort chronologically\n } catch {\n return [];\n }\n}\n\n/** Replay one JSONL text into `doc`, skipping records at/before the baseline. */\nfunction replayText(doc: ProfileDoc, text: string, baselineTs: string, stats: { records: number; truncatedTail: number; isLive: boolean }): void {\n const lines = text.split('\\n');\n for (let i = 0; i < lines.length; i++) {\n const trimmed = lines[i]!.trim();\n if (!trimmed) continue;\n try {\n const rec = JSON.parse(trimmed) as JournalRecord;\n // Baseline skip: only records CARRYING a ts can be proven folded. A\n // ts-less record is always applied (applyOpPermissive tolerates it).\n if (baselineTs && rec.ts && String(rec.ts) <= baselineTs) continue;\n for (const op of rec.applied ?? []) applyOpPermissive(doc, op, rec.ts);\n stats.records += 1;\n } catch {\n // Torn tail only counts on the LIVE journal — archives are closed files.\n const isLast = lines.slice(i + 1).every((l) => !l.trim());\n if (stats.isLive && isLast) {\n stats.truncatedTail = lines.length - i;\n break;\n }\n // mid-file corrupt record: skip (journal stays append-only/immutable)\n }\n }\n}\n\n/** Full replay: snapshot basepoint + archive shards + live journal. */\nexport function replayJournal(guard: PathGuard, dataDir: string): ReplayResult {\n const snap = loadSnapshot(guard, dataDir);\n const doc = snap ? snap.doc : emptyProfile();\n const baselineTs = snap?.baselineTs ?? '';\n const stats = { records: snap?.recordsFolded ?? 0, truncatedTail: 0, isLive: false };\n for (const file of listArchiveFiles(guard, dataDir)) {\n try {\n // shard record counts are not reported (the snapshot already folded\n // them); only the live journal's torn tail is meaningful.\n replayText(doc, fs.readFileSync(path.join(dataDir, file), 'utf8'), baselineTs, { records: 0, truncatedTail: 0, isLive: false });\n } catch { /* unreadable shard: skip */ }\n }\n stats.isLive = true;\n replayText(doc, readText(guard, journalFilePath(dataDir), ''), baselineTs, stats);\n return { doc, truncatedTail: stats.truncatedTail, records: stats.records };\n}\n\nexport function loadProfile(guard: PathGuard, file: string): ProfileDoc {\n const doc = loadJson<ProfileDoc>(guard, file);\n if (!doc || !doc.partitions) return emptyProfile();\n // ensure all partitions exist\n for (const p of PARTITIONS) {\n if (!doc.partitions[p]) doc.partitions[p] = { entries: [] };\n }\n return doc;\n}\n\nfunction parseIso(v: string): number {\n const t = Date.parse(v);\n return Number.isFinite(t) ? t : 0;\n}\n\n/** ref format \"<datafile>#<locator>\": the referenced file must exist under data/. */\nfunction refExists(guard: PathGuard, dataDir: string, ref: string): boolean {\n const base = ref.split('#')[0] ?? '';\n if (!base) return false;\n const target = path.join(dataDir, base);\n try {\n return fs.existsSync(guard.assert(target));\n } catch {\n return false;\n }\n}\n\nfunction capForKinds(kinds: EvidenceKind[]): number {\n if (kinds.length === 0) return 0.4;\n return Math.min(...kinds.map((k) => CONFIDENCE_CAP[k] ?? 0.4));\n}\n\nfunction findActive(doc: ProfileDoc, id: string): ProfileEntry | undefined {\n for (const p of PARTITIONS) {\n const hit = doc.partitions[p]!.entries.find((e) => e.id === id && e.validTo === null);\n if (hit) return hit;\n }\n return undefined;\n}\n\n/**\n * Apply validated ops to the doc (mutates). Returns applied/rejected.\n * Guards (§3.3): whitelist, evidence gate, per-run ops cap is enforced by the\n * caller, confidence caps by evidence kind, psy gating, INVALIDATE ownership:\n * volatile expiry is code-driven (LLM may not), stable invalidation needs a\n * contradicting observation attached.\n */\nexport function applyOpsToDoc(\n guard: PathGuard,\n dataDir: string,\n doc: ProfileDoc,\n ops: ProfileOp[],\n schema: ProfileSchema,\n policy: Policy,\n now: number,\n): ApplyReport {\n const applied: ProfileOp[] = [];\n const rejected: { op: ProfileOp; reason: string }[] = [];\n const nowIso = new Date(now).toISOString();\n\n for (const op of ops) {\n if (op.op === 'NOOP') {\n applied.push(op);\n continue;\n }\n if (op.op === 'ADD') {\n if (op.partition === 'psy' && !policy.profile.psyEnabled) {\n rejected.push({ op, reason: 'psy partition is disabled' });\n continue;\n }\n const check = checkAddAgainstSchema(schema, op.partition, op.topic, op.subTopic, op.temporal);\n if (!check.ok) {\n rejected.push({ op, reason: check.reason! });\n continue;\n }\n if (!op.evidence || op.evidence.length === 0) {\n rejected.push({ op, reason: 'ADD without evidence (no provenance, axiom 1)' });\n continue;\n }\n const badRef = op.evidence.find((e) => !refExists(guard, dataDir, e.ref));\n if (badRef) {\n rejected.push({ op, reason: `evidence ref does not resolve: ${badRef.ref}` });\n continue;\n }\n const cap = capForKinds(op.evidence.map((e) => e.kind));\n const active = doc.partitions[op.partition]!.entries.filter((e) => e.validTo === null);\n if (active.length >= policy.profile.partitionCap) {\n rejected.push({ op, reason: `partition ${op.partition} at cap (${policy.profile.partitionCap}); converge first` });\n continue;\n }\n dbSeq += 1;\n const entry: ProfileEntry = {\n id: `p${dbSeq.toString(36)}${randomUUID().slice(0, 4)}`,\n partition: op.partition,\n topic: op.topic,\n subTopic: op.subTopic,\n content: op.content.trim(),\n confidence: Math.min(op.confidence ?? cap, cap),\n temporal: check.temporal,\n validFrom: nowIso,\n validTo: null,\n supersededBy: null,\n evidence: op.evidence,\n createdAt: nowIso,\n updatedAt: nowIso,\n updateCount: 0,\n };\n op.assignedId = entry.id; // journal replay must reproduce this id\n doc.partitions[op.partition]!.entries.push(entry);\n applied.push(op);\n continue;\n }\n if (op.op === 'UPDATE') {\n const entry = findActive(doc, op.id);\n if (!entry) {\n rejected.push({ op, reason: `unknown or inactive entry: ${op.id}` });\n continue;\n }\n if (op.changes.content !== undefined) entry.content = op.changes.content.trim();\n if (op.changes.confidence !== undefined) {\n const cap = capForKinds(entry.evidence.map((e) => e.kind));\n // confidence upgrades need a second confirming observation (§3.3):\n // only allowed up to cap, and only when the entry already has 2+ evidence\n if (op.changes.confidence > entry.confidence && entry.evidence.length < 2) {\n rejected.push({ op, reason: 'confidence upgrade requires a second confirming observation' });\n continue;\n }\n entry.confidence = Math.min(op.changes.confidence, cap);\n }\n entry.updatedAt = nowIso;\n entry.updateCount += 1;\n applied.push(op);\n continue;\n }\n if (op.op === 'INVALIDATE') {\n const entry = findActive(doc, op.id);\n if (!entry) {\n rejected.push({ op, reason: `unknown or inactive entry: ${op.id}` });\n continue;\n }\n if (entry.temporal === 'volatile') {\n rejected.push({ op, reason: 'volatile expiry is code-owned (time-driven), not LLM-nominated' });\n continue;\n }\n // stable: rebuttal-driven; requires a contradicting observation attached\n const hasNewObservation = (op.evidence ?? []).length > 0\n && (op.evidence ?? []).some((e) => parseIso(e.at) > parseIso(entry.evidence[entry.evidence.length - 1]?.at ?? ''));\n if (!hasNewObservation) {\n rejected.push({ op, reason: 'stable INVALIDATE requires a newer contradicting observation' });\n continue;\n }\n entry.validTo = nowIso;\n entry.supersededBy = null;\n entry.updatedAt = nowIso;\n entry.updateCount += 1;\n if (op.evidence) entry.evidence.push(...op.evidence);\n applied.push(op);\n continue;\n }\n }\n return { applied, rejected };\n}\n\nlet dbSeq = 0;\n\n/** Deterministic aging (D9): volatile expiry + stable low-activity marking. */\nexport function runDeterministicAging(\n doc: ProfileDoc,\n policy: Policy,\n now: number,\n): { volatileExpired: number; lowActivityMarked: number } {\n const nowIso = new Date(now).toISOString();\n let volatileExpired = 0;\n let lowActivityMarked = 0;\n for (const p of PARTITIONS) {\n for (const e of doc.partitions[p]!.entries) {\n if (e.validTo !== null) continue;\n const lastEvidence = Math.max(...e.evidence.map((x) => parseIso(x.at)), parseIso(e.updatedAt));\n if (e.temporal === 'volatile') {\n if (now - lastEvidence > policy.profile.volatileDays * DAY_MS) {\n e.validTo = nowIso;\n e.updatedAt = nowIso;\n e.updateCount += 1;\n volatileExpired += 1;\n }\n } else if (!e.lowActivity && now - lastEvidence > policy.profile.stableLowActivityDays * DAY_MS) {\n e.lowActivity = true;\n lowActivityMarked += 1;\n }\n }\n }\n return { volatileExpired, lowActivityMarked };\n}\n\n/** Persist the materialized view atomically + append the journal record. */\nexport function persistWithJournal(\n guard: PathGuard,\n dataDir: string,\n doc: ProfileDoc,\n record: Omit<JournalRecord, 'ts'>,\n): void {\n saveJson(guard, profileFilePath(dataDir), doc);\n const line = JSON.stringify({ ts: new Date().toISOString(), ...record });\n const journal = journalFilePath(dataDir);\n try {\n fs.appendFileSync(guard.assert(journal), line + '\\n', 'utf8');\n } catch {\n fs.mkdirSync(dataDir, { recursive: true });\n fs.appendFileSync(guard.assert(journal), line + '\\n', 'utf8');\n }\n}\n\n// ── journal replay (verify / rebuild, r2 §14) ───────────────────────────\n\nfunction applyOpPermissive(doc: ProfileDoc, op: ProfileOp, ts: string): void {\n // Journal is trusted history: replay applies without revalidation.\n if (op.op === 'ADD') {\n dbSeq += 1;\n doc.partitions[op.partition]!.entries.push({\n id: op.assignedId ?? `r${dbSeq.toString(36)}${randomUUID().slice(0, 4)}`,\n partition: op.partition,\n topic: op.topic,\n subTopic: op.subTopic,\n content: op.content,\n confidence: op.confidence ?? 0.5,\n temporal: op.temporal ?? 'stable',\n validFrom: ts,\n validTo: null,\n supersededBy: null,\n evidence: op.evidence,\n createdAt: ts,\n updatedAt: ts,\n updateCount: 0,\n });\n return;\n }\n if (op.op === 'UPDATE') {\n const e = [...PARTITIONS].flatMap((p) => doc.partitions[p]!.entries).find((x) => x.id === op.id);\n if (e) {\n if (op.changes.content !== undefined) e.content = op.changes.content;\n if (op.changes.confidence !== undefined) e.confidence = op.changes.confidence;\n e.updatedAt = ts;\n e.updateCount += 1;\n }\n return;\n }\n if (op.op === 'INVALIDATE') {\n const e = [...PARTITIONS].flatMap((p) => doc.partitions[p]!.entries).find((x) => x.id === op.id);\n if (e) {\n e.validTo = ts;\n e.updatedAt = ts;\n e.updateCount += 1;\n }\n }\n // NOOP: nothing\n}\n\nexport interface ReplayResult {\n doc: ProfileDoc;\n truncatedTail: number;\n records: number;\n}\n\nexport interface VerifyReport {\n ok: boolean;\n firstDivergence?: { id: string; expected: string; actual: string };\n truncatedTail: number;\n records: number;\n}\n\n/** profile verify: replay vs disk, report first divergence, never fix. */\nexport function verifyProfile(guard: PathGuard, dataDir: string): VerifyReport {\n const replayed = replayJournal(guard, dataDir);\n const onDisk = loadProfile(guard, profileFilePath(dataDir));\n // Timestamps legitimately differ (journal record ts >= op ts); identity\n // fields are also normalized. Compare semantic content only.\n const strip = (doc: ProfileDoc): string =>\n JSON.stringify(doc.partitions, (k, v) => (['id', 'supersededBy', 'validFrom', 'createdAt', 'updatedAt', 'retiredAt'].includes(k) ? '<norm>' : v));\n const ok = strip(replayed.doc) === strip(onDisk);\n if (ok) return { ok: true, truncatedTail: replayed.truncatedTail, records: replayed.records };\n // first divergence: first entry id present in only one view\n const diskIds = new Set([...PARTITIONS].flatMap((p) => onDisk.partitions[p]!.entries.map((e) => e.content))); const replayIds = new Set([...PARTITIONS].flatMap((p) => replayed.doc.partitions[p]!.entries.map((e) => e.content)));\n const onlyDisk = [...diskIds].find((c) => !replayIds.has(c));\n const onlyReplay = [...replayIds].find((c) => !diskIds.has(c));\n return {\n ok: false,\n firstDivergence: {\n id: onlyDisk ?? onlyReplay ?? '(content)',\n expected: onlyReplay ? 'absent in journal replay' : 'present in journal replay',\n actual: onlyDisk ? 'present on disk' : 'absent on disk',\n },\n truncatedTail: replayed.truncatedTail,\n records: replayed.records,\n };\n}\n\nexport interface RebuildReport {\n ok: boolean;\n truncatedTail: number;\n records: number;\n wrote: boolean;\n}\n\n/** profile rebuild: journal is authoritative; atomic replace; torn tail reported. */\nexport function rebuildProfile(\n guard: PathGuard,\n dataDir: string,\n opts: { check?: boolean } = {},\n): RebuildReport & { diffSummary?: string } {\n const replayed = replayJournal(guard, dataDir);\n const target = profileFilePath(dataDir);\n if (opts.check) {\n const onDisk = loadProfile(guard, target);\n const same = JSON.stringify(onDisk) === JSON.stringify(replayed.doc);\n return {\n ok: same,\n truncatedTail: replayed.truncatedTail,\n records: replayed.records,\n wrote: false,\n diffSummary: same ? 'no diff' : 'materialized view differs from journal replay',\n };\n }\n saveJson(guard, target, replayed.doc);\n if (replayed.truncatedTail > 0) {\n // explicit audit: never silently rebuild a view that lost its tail\n writeText(\n guard,\n path.join(dataDir, 'logs', 'rebuild-report.txt'),\n `rebuild truncated ${replayed.truncatedTail} torn line(s) at journal tail; ${replayed.records} records applied\\n`,\n );\n }\n return { ok: true, truncatedTail: replayed.truncatedTail, records: replayed.records, wrote: true };\n}\n","// User profile types (design doc §3). Fourth store: warm, structured,\n// slow-evolving model of the user. Not the material pool (hot cache), not\n// DSH long-term memory (conversation-validated layer).\n\nexport type Partition = 'interest' | 'projects' | 'comm' | 'psy';\nexport type Temporal = 'volatile' | 'stable';\nexport type EvidenceKind = 'chat' | 'screen' | 'browse' | 'hand' | 'ledger';\n\nexport interface Evidence {\n kind: EvidenceKind;\n at: string;\n /** Pointer to an existing audit/log location, e.g. \"heartbeat.jsonl#2026-09-06T12:00:00Z\". */\n ref: string;\n /** At most ONE short quote (<=1 sentence). Never raw conversation/screen text. */\n quote?: string;\n}\n\nexport interface ProfileEntry {\n id: string;\n partition: Partition;\n topic: string;\n subTopic: string;\n content: string;\n /** 0..1; capped per source kind (chat .6 / screen .4 / browse .4). */\n confidence: number;\n temporal: Temporal;\n validFrom: string;\n validTo: string | null;\n supersededBy: string | null;\n evidence: Evidence[];\n createdAt: string;\n updatedAt: string;\n updateCount: number;\n /** stable-tier audit flag (180d without observation): digest deprioritizes. */\n lowActivity?: boolean;\n}\n\nexport interface ProfileDoc {\n version: number;\n partitions: Record<Partition, { entries: ProfileEntry[] }>;\n}\n\nexport interface InboxItem {\n id?: string;\n kind: EvidenceKind;\n at: string;\n ref: string;\n /** <= 1 short sentence; never raw conversation/screen text (truncated by writer). */\n note: string;\n}\n\nexport type ProfileOp =\n | {\n op: 'ADD';\n partition: Partition;\n topic: string;\n subTopic: string;\n content: string;\n temporal?: Temporal;\n confidence?: number;\n why: string;\n evidence: Evidence[];\n /** Assigned by the store at apply time so journal replay preserves ids. */\n assignedId?: string;\n }\n | { op: 'UPDATE'; id: string; changes: { content?: string; confidence?: number }; why: string }\n | { op: 'INVALIDATE'; id: string; why: string; evidence?: Evidence[] }\n | { op: 'NOOP'; why: string };\n\nexport interface JournalRecord {\n ts: string;\n runId: string;\n applied: ProfileOp[];\n rejected: { op: ProfileOp; reason: string }[];\n}\n\nexport interface ApplyReport {\n applied: ProfileOp[];\n rejected: { op: ProfileOp; reason: string }[];\n}\n\nexport const PARTITIONS: readonly Partition[] = ['interest', 'projects', 'comm', 'psy'];\n\nexport const CONFIDENCE_CAP: Record<EvidenceKind, number> = {\n chat: 0.6,\n screen: 0.4,\n browse: 0.4,\n hand: 1.0,\n ledger: 0.6,\n};\n\nexport function emptyProfile(): ProfileDoc {\n return {\n version: 1,\n partitions: { interest: { entries: [] }, projects: { entries: [] }, comm: { entries: [] }, psy: { entries: [] } },\n };\n}\n","// profile-schema.json loading + ADD validation (r4 B10: temporal tier is an\n// ENTRY-level attribute; the schema declares, per sub_topic, the ALLOWED tier\n// set and the DEFAULT. Unlisted defaults to 'stable'.)\n\nimport fs from 'node:fs';\nimport path from 'node:path';\nimport type { Partition, Temporal } from './types.js';\n\nexport interface SubTopicDecl {\n allowed?: Temporal[];\n default?: Temporal;\n}\n\nexport interface ProfileSchema {\n version: number;\n partitions: Partial<Record<Partition, {\n topics: Record<string, { subtopics: Record<string, SubTopicDecl> }>;\n }>>;\n}\n\nexport function loadProfileSchema(paths: { configDir: string; settingsDir: string }): ProfileSchema {\n const userPath = path.join(paths.settingsDir, 'profile-schema.json');\n const file = fs.existsSync(userPath) ? userPath : path.join(paths.configDir, 'profile-schema.json');\n try {\n const raw = JSON.parse(fs.readFileSync(file, 'utf8')) as ProfileSchema;\n if (!raw.partitions) throw new Error('partitions missing');\n return raw;\n } catch (e) {\n throw new Error(`profile-schema unreadable at ${file}: ${String(e)}`);\n }\n}\n\nexport interface SchemaCheck {\n ok: boolean;\n reason?: string;\n temporal: Temporal;\n}\n\n/**\n * Validate an ADD against the whitelist and resolve the entry's temporal tier:\n * LLM nominates within the sub_topic's allowed set; missing nomination falls\n * back to the declared default; fully unlisted -> reject (charter boundary).\n */\nexport function checkAddAgainstSchema(\n schema: ProfileSchema,\n partition: Partition,\n topic: string,\n subTopic: string,\n nominated?: Temporal,\n): SchemaCheck {\n const p = schema.partitions[partition];\n if (!p) return { ok: false, reason: `partition not in schema: ${partition}`, temporal: 'stable' };\n const t = p.topics[topic];\n if (!t) return { ok: false, reason: `topic not in schema: ${partition}/${topic}`, temporal: 'stable' };\n const st = t.subtopics[subTopic];\n if (!st) return { ok: false, reason: `sub_topic not in schema: ${partition}/${topic}/${subTopic}`, temporal: 'stable' };\n const allowed: Temporal[] = st.allowed && st.allowed.length > 0 ? st.allowed : ['stable'];\n const def: Temporal = st.default && allowed.includes(st.default) ? st.default : allowed[0]!;\n if (!nominated) return { ok: true, temporal: def };\n if (!allowed.includes(nominated)) {\n return {\n ok: false,\n reason: `temporal \"${nominated}\" not allowed for ${partition}/${topic}/${subTopic} (allowed: ${allowed.join('|')})`,\n temporal: def,\n };\n }\n return { ok: true, temporal: nominated };\n}\n"],"mappings":"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","names":["fs","path","fs","path","path","randomUUID","fs","fs","path","path","fs","randomUUID"]}
|
package/dist/cli/index.js
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
BUNDLED_PRESET_ID,
|
|
3
3
|
adviseWander,
|
|
4
|
-
appendAuditLine,
|
|
5
4
|
appendEntry,
|
|
6
5
|
browseStatus,
|
|
7
6
|
checkWatchlist,
|
|
@@ -12,21 +11,18 @@ import {
|
|
|
12
11
|
ensureRegistered,
|
|
13
12
|
installBundledPreset,
|
|
14
13
|
ledgerFilePath,
|
|
14
|
+
listWeeklyReports,
|
|
15
15
|
loadInterests,
|
|
16
16
|
loadPolicy,
|
|
17
|
-
loadProfile,
|
|
18
17
|
loadWatchlist,
|
|
19
18
|
markDone,
|
|
20
19
|
presetStatus,
|
|
21
|
-
profileFilePath,
|
|
22
|
-
pruneAuditFile,
|
|
23
20
|
readLedger,
|
|
24
|
-
|
|
21
|
+
readWeeklyReport,
|
|
25
22
|
scanPending,
|
|
26
23
|
sendNewMessageHint,
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
} from "../chunk-ON4MSU6E.js";
|
|
24
|
+
weeklyDirPath
|
|
25
|
+
} from "../chunk-2SYXKKZF.js";
|
|
30
26
|
import {
|
|
31
27
|
activeSeeds,
|
|
32
28
|
addSeed,
|
|
@@ -36,12 +32,27 @@ import {
|
|
|
36
32
|
loadPool,
|
|
37
33
|
seedsFilePath,
|
|
38
34
|
surfaceSeed
|
|
39
|
-
} from "../chunk-
|
|
35
|
+
} from "../chunk-PQTSXW4F.js";
|
|
36
|
+
import {
|
|
37
|
+
appendAuditLine,
|
|
38
|
+
loadProfile,
|
|
39
|
+
profileFilePath,
|
|
40
|
+
pruneAuditFile,
|
|
41
|
+
rebuildProfile,
|
|
42
|
+
shredFileSync,
|
|
43
|
+
verifyProfile
|
|
44
|
+
} from "../chunk-VIZNIQLK.js";
|
|
45
|
+
import {
|
|
46
|
+
applyMigrationEntries,
|
|
47
|
+
collectMigrationEntries,
|
|
48
|
+
decryptContainer,
|
|
49
|
+
encryptContainer
|
|
50
|
+
} from "../chunk-IPOZFZPY.js";
|
|
40
51
|
import {
|
|
41
52
|
initWorkspace,
|
|
42
53
|
loadEncryptedText,
|
|
43
54
|
writeText
|
|
44
|
-
} from "../chunk-
|
|
55
|
+
} from "../chunk-IFTFDHZX.js";
|
|
45
56
|
|
|
46
57
|
// src/cli/index.ts
|
|
47
58
|
import { spawn } from "child_process";
|
|
@@ -161,7 +172,12 @@ function usage() {
|
|
|
161
172
|
" profile export decrypted Markdown export to data/exports/",
|
|
162
173
|
" profile verify journal replay vs disk (report only)",
|
|
163
174
|
" profile rebuild [--check] rebuild materialized view from journal",
|
|
175
|
+
" profile snapshot [--force] fold the journal into a snapshot + archive shard",
|
|
164
176
|
" profile wipe wipe profile data (asks --yes)",
|
|
177
|
+
" weekly list list generated weekly reports",
|
|
178
|
+
" weekly show [file] print a report (default: newest)",
|
|
179
|
+
" migrate export [file] pack memory files into a passphrase container (passphrase: 2 stdin lines)",
|
|
180
|
+
" migrate import <file> restore a container into this workspace (passphrase: 1 stdin line)",
|
|
165
181
|
" burn [--yes] [--all] shred runtime data (settings kept unless --all)",
|
|
166
182
|
" preset status bundled agent preset: target dir + installed?",
|
|
167
183
|
" preset install [--force] install the bundled preset (never overwrites unless --force)"
|
|
@@ -178,6 +194,14 @@ function flag(argv, name) {
|
|
|
178
194
|
const i = argv.indexOf(name);
|
|
179
195
|
return i > -1 ? argv[i + 1] : void 0;
|
|
180
196
|
}
|
|
197
|
+
async function readLines(prompts) {
|
|
198
|
+
const readline = await import("readline/promises");
|
|
199
|
+
const it = readline.createInterface({ input: process.stdin });
|
|
200
|
+
const out = [];
|
|
201
|
+
for (const p of prompts) out.push((await it.question(p)).trim());
|
|
202
|
+
it.close();
|
|
203
|
+
return out;
|
|
204
|
+
}
|
|
181
205
|
async function main(argv) {
|
|
182
206
|
const [cmd, sub, ...rest] = argv;
|
|
183
207
|
if (!cmd || cmd === "help" || cmd === "--help") {
|
|
@@ -190,6 +214,12 @@ async function main(argv) {
|
|
|
190
214
|
const seedsFile = seedsFilePath(paths.dataDir);
|
|
191
215
|
const ledgerFile = ledgerFilePath(paths.dataDir);
|
|
192
216
|
const decisionLog = path2.join(paths.logsDir, "heartbeat.jsonl");
|
|
217
|
+
const seedAudit = (entry) => {
|
|
218
|
+
try {
|
|
219
|
+
appendAuditLine(decisionLog, entry);
|
|
220
|
+
} catch {
|
|
221
|
+
}
|
|
222
|
+
};
|
|
193
223
|
switch (cmd) {
|
|
194
224
|
case "status": {
|
|
195
225
|
console.log(JSON.stringify({
|
|
@@ -216,7 +246,7 @@ async function main(argv) {
|
|
|
216
246
|
source: flag(rest, "--source"),
|
|
217
247
|
topic: flag(rest, "--topic"),
|
|
218
248
|
confidence: flag(rest, "--confidence") ? Number(flag(rest, "--confidence")) : void 0
|
|
219
|
-
});
|
|
249
|
+
}, Date.now(), seedAudit);
|
|
220
250
|
if (result.kind === "duplicate") {
|
|
221
251
|
console.log(`DUPLICATE: active seed ${result.seed.id} has the same text`);
|
|
222
252
|
return 0;
|
|
@@ -235,7 +265,7 @@ async function main(argv) {
|
|
|
235
265
|
return 0;
|
|
236
266
|
}
|
|
237
267
|
case "surface": {
|
|
238
|
-
const s = surfaceSeed(guard, seedsFile, policy, rest[0] ?? "");
|
|
268
|
+
const s = surfaceSeed(guard, seedsFile, policy, rest[0] ?? "", Date.now(), seedAudit);
|
|
239
269
|
if (!s) {
|
|
240
270
|
console.log("NOT_FOUND");
|
|
241
271
|
return 1;
|
|
@@ -244,7 +274,7 @@ async function main(argv) {
|
|
|
244
274
|
return 0;
|
|
245
275
|
}
|
|
246
276
|
case "archive": {
|
|
247
|
-
const s = archiveSeedById(guard, seedsFile, rest[0] ?? "");
|
|
277
|
+
const s = archiveSeedById(guard, seedsFile, rest[0] ?? "", "completed", Date.now(), seedAudit);
|
|
248
278
|
if (!s) {
|
|
249
279
|
console.log("NOT_FOUND");
|
|
250
280
|
return 1;
|
|
@@ -253,8 +283,8 @@ async function main(argv) {
|
|
|
253
283
|
return 0;
|
|
254
284
|
}
|
|
255
285
|
case "gc": {
|
|
256
|
-
const report = gcPool(guard, seedsFile, policy);
|
|
257
|
-
console.log(`GC consumed:${report.consumed} expired:${report.expired} cold_bench:${report.coldBench} -> active ${report.activeAfter}/${policy.seeds.maxActive}`);
|
|
286
|
+
const report = gcPool(guard, seedsFile, policy, Date.now(), seedAudit);
|
|
287
|
+
console.log(`GC consumed:${report.consumed} expired:${report.expired} cold_bench:${report.coldBench} archive_trimmed:${report.archiveTrimmed} -> active ${report.activeAfter}/${policy.seeds.maxActive} archive ${archivedSeeds(loadPool(guard, seedsFile)).length}/${policy.seeds.archiveCap}`);
|
|
258
288
|
return 0;
|
|
259
289
|
}
|
|
260
290
|
case "stats": {
|
|
@@ -320,6 +350,31 @@ async function main(argv) {
|
|
|
320
350
|
return 1;
|
|
321
351
|
}
|
|
322
352
|
}
|
|
353
|
+
case "weekly": {
|
|
354
|
+
const reports = listWeeklyReports(guard, paths.dataDir);
|
|
355
|
+
if (sub === "list" || sub === void 0) {
|
|
356
|
+
if (reports.length === 0) console.log("(no reports yet \u2014 heartbeat generates one every 7 days)");
|
|
357
|
+
for (const r of reports) console.log(`${r.file} ${r.start.slice(0, 10)} ~ ${r.end.slice(0, 10)} [${r.source}]`);
|
|
358
|
+
return 0;
|
|
359
|
+
}
|
|
360
|
+
if (sub === "show") {
|
|
361
|
+
const file = rest[0] ?? reports[0]?.file;
|
|
362
|
+
if (!file) {
|
|
363
|
+
console.log("(no reports yet)");
|
|
364
|
+
return 1;
|
|
365
|
+
}
|
|
366
|
+
const rep = readWeeklyReport(guard, paths.dataDir, file);
|
|
367
|
+
if (!rep) {
|
|
368
|
+
console.error(`no such report: ${file} (see: weekly list; files live in ${weeklyDirPath(paths.dataDir)})`);
|
|
369
|
+
return 1;
|
|
370
|
+
}
|
|
371
|
+
console.log(`# ${rep.start.slice(0, 10)} ~ ${rep.end.slice(0, 10)} [${rep.source}]`);
|
|
372
|
+
console.log(rep.text);
|
|
373
|
+
return 0;
|
|
374
|
+
}
|
|
375
|
+
console.error(`unknown weekly subcommand: ${sub}`);
|
|
376
|
+
return 1;
|
|
377
|
+
}
|
|
323
378
|
case "logs": {
|
|
324
379
|
if (sub !== "cleanup") {
|
|
325
380
|
console.error("usage: logs cleanup [--dry-run]");
|
|
@@ -450,6 +505,23 @@ async function main(argv) {
|
|
|
450
505
|
console.log("WIPED (settings preserved; use burn for full shredding)");
|
|
451
506
|
return 0;
|
|
452
507
|
}
|
|
508
|
+
case "snapshot": {
|
|
509
|
+
const { snapshotDue, snapshotProfile, SNAPSHOT_THRESHOLD } = await import("../snapshot-ZBCSX67Y.js");
|
|
510
|
+
const { needed, lines } = snapshotDue(guard, paths.dataDir);
|
|
511
|
+
console.log(`journal ${lines} \u6761\uFF08\u9608\u503C ${SNAPSHOT_THRESHOLD}\uFF09`);
|
|
512
|
+
if (!needed && !rest.includes("--force")) {
|
|
513
|
+
console.log("\u672A\u5230\u9608\u503C\uFF0C\u672A\u6267\u884C\uFF08\u52A0 --force \u5F3A\u5236\u6298\u53E0\uFF09\u3002");
|
|
514
|
+
return 0;
|
|
515
|
+
}
|
|
516
|
+
const report = snapshotProfile(guard, paths.dataDir);
|
|
517
|
+
if (!report.ok) {
|
|
518
|
+
console.log(`\u672A\u6267\u884C\uFF1A${report.reason}`);
|
|
519
|
+
return 0;
|
|
520
|
+
}
|
|
521
|
+
console.log(`\u5DF2\u6298\u53E0 ${report.folded} \u6761 \u2192 \u5FEB\u7167\uFF08baseline ${report.baselineTs}\uFF09\uFF0C\u5F52\u6863 ${report.archiveFile}\uFF0Clive journal \u5DF2\u6E05\u7A7A\u3002`);
|
|
522
|
+
console.log("verify/rebuild \u81EA\u52A8\u4ECE\u5FEB\u7167\u57FA\u70B9\u91CD\u653E\uFF0C\u65E0\u9700\u989D\u5916\u64CD\u4F5C\u3002");
|
|
523
|
+
return 0;
|
|
524
|
+
}
|
|
453
525
|
default:
|
|
454
526
|
console.error(`unknown profile subcommand: ${sub}`);
|
|
455
527
|
return 1;
|
|
@@ -469,6 +541,68 @@ async function main(argv) {
|
|
|
469
541
|
console.log(`BURNED: ${result.burned.length} \u9879\uFF1BMISSING: ${result.missing.length} \u9879`);
|
|
470
542
|
return 0;
|
|
471
543
|
}
|
|
544
|
+
case "migrate": {
|
|
545
|
+
if (sub === "export") {
|
|
546
|
+
const defaultOut = path2.join(paths.exportsDir, `heartbeat-memory-${(/* @__PURE__ */ new Date()).toISOString().slice(0, 10)}.hbmig`);
|
|
547
|
+
const outfile = rest[0] ?? defaultOut;
|
|
548
|
+
let outCanon;
|
|
549
|
+
try {
|
|
550
|
+
outCanon = guard.assert(outfile);
|
|
551
|
+
} catch {
|
|
552
|
+
console.error(`\u5BFC\u51FA\u6587\u4EF6\u5FC5\u987B\u843D\u5728\u63D2\u4EF6 data/ \u76EE\u5F55\u5185\uFF08\u8DEF\u5F84\u5B88\u536B\u62D2\u7EDD\uFF09\uFF1A${outfile}
|
|
553
|
+
\u9ED8\u8BA4\u4F4D\u7F6E\uFF1A${defaultOut}`);
|
|
554
|
+
return 1;
|
|
555
|
+
}
|
|
556
|
+
const [pw1, pw2] = await readLines(["\u8BBE\u7F6E\u53E3\u4EE4\uFF08\u7528\u4E8E\u52A0\u5BC6\u8FC1\u79FB\u5305\uFF09: ", "\u518D\u8F93\u5165\u4E00\u6B21\u786E\u8BA4: "]);
|
|
557
|
+
if (!pw1 || pw1 !== pw2) {
|
|
558
|
+
console.error("\u4E24\u6B21\u8F93\u5165\u4E0D\u4E00\u81F4\u6216\u4E3A\u7A7A\uFF0C\u5DF2\u53D6\u6D88\u3002");
|
|
559
|
+
return 1;
|
|
560
|
+
}
|
|
561
|
+
const { entries, progress } = collectMigrationEntries(guard, paths);
|
|
562
|
+
if (entries.length === 0) {
|
|
563
|
+
console.log("\u6CA1\u6709\u53EF\u6253\u5305\u7684\u8BB0\u5FC6\u6587\u4EF6\uFF08data/ \u662F\u7A7A\u7684\uFF09\u3002");
|
|
564
|
+
return 1;
|
|
565
|
+
}
|
|
566
|
+
fs2.mkdirSync(path2.dirname(outCanon), { recursive: true });
|
|
567
|
+
fs2.writeFileSync(outCanon, encryptContainer(entries, pw1), "utf8");
|
|
568
|
+
console.log(`\u5DF2\u6253\u5305 ${entries.length} \u4E2A\u6587\u4EF6 \u2192 ${outCanon}`);
|
|
569
|
+
console.log(` \u6253\u5305\uFF1A${progress.packed.join(", ")}`);
|
|
570
|
+
if (progress.missing.length > 0) console.log(` \u8DF3\u8FC7\uFF08\u4E0D\u5B58\u5728\uFF09\uFF1A${progress.missing.join(", ")}`);
|
|
571
|
+
console.log("\u5BB9\u5668\u662F\u53E3\u4EE4\u52A0\u5BC6\u7684\uFF0C\u53EF\u5B89\u5168\u62F7\u8D1D\u5230\u65B0\u673A\u5668\uFF1BDPAPI \u4F1A\u5728\u5BFC\u5165\u65F6\u7528\u65B0\u673A\u5668\u91CD\u65B0\u52A0\u5BC6\u3002");
|
|
572
|
+
return 0;
|
|
573
|
+
}
|
|
574
|
+
if (sub === "import") {
|
|
575
|
+
const infile = rest[0];
|
|
576
|
+
if (!infile) {
|
|
577
|
+
console.error("usage: migrate import <container-file>");
|
|
578
|
+
return 1;
|
|
579
|
+
}
|
|
580
|
+
const [pw] = await readLines(["\u8F93\u5165\u8FC1\u79FB\u5305\u53E3\u4EE4: "]);
|
|
581
|
+
let text;
|
|
582
|
+
try {
|
|
583
|
+
text = fs2.readFileSync(infile, "utf8");
|
|
584
|
+
} catch {
|
|
585
|
+
console.error(`\u8BFB\u4E0D\u5230\u8FC1\u79FB\u5305\uFF1A${infile}`);
|
|
586
|
+
return 1;
|
|
587
|
+
}
|
|
588
|
+
let files;
|
|
589
|
+
try {
|
|
590
|
+
files = decryptContainer(text, pw ?? "");
|
|
591
|
+
} catch (e) {
|
|
592
|
+
console.error(String(e instanceof Error ? e.message : e));
|
|
593
|
+
return 1;
|
|
594
|
+
}
|
|
595
|
+
const result = applyMigrationEntries(guard, paths, files.files);
|
|
596
|
+
console.log(`\u6062\u590D ${result.restored.length} \u4E2A\u6587\u4EF6\uFF1B\u5907\u4EFD ${result.backedUp.length} \u4E2A\u88AB\u8986\u76D6\u6587\u4EF6\uFF1B\u8DF3\u8FC7 ${result.skipped.length} \u4E2A\u3002`);
|
|
597
|
+
for (const r of result.restored) console.log(` \u6062\u590D: ${r}`);
|
|
598
|
+
for (const b of result.backedUp) console.log(` \u5907\u4EFD: ${b}.bak-migrate-*`);
|
|
599
|
+
if (result.skipped.length > 0) console.log(` \u8DF3\u8FC7: ${result.skipped.join(", ")}`);
|
|
600
|
+
console.log("\u91CD\u542F DSH \u540E\u751F\u6548\u3002");
|
|
601
|
+
return 0;
|
|
602
|
+
}
|
|
603
|
+
console.error(`unknown migrate subcommand: ${sub}`);
|
|
604
|
+
return 1;
|
|
605
|
+
}
|
|
472
606
|
case "sessions": {
|
|
473
607
|
const root = path2.join(os.homedir(), ".dsh", "sessions");
|
|
474
608
|
let found = 0;
|
package/dist/cli/index.js.map
CHANGED
|
@@ -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.\r\n// Run: node dist/cli/index.js <command> [args] (or via tsx in dev)\r\n\r\nimport { spawn } from 'node:child_process';\r\nimport fs from 'node:fs';\r\nimport os from 'node:os';\r\nimport path from 'node:path';\r\nimport { initWorkspace, workspace } from '../core/paths.js';\r\nimport { createPathGuard } from '../core/path-guard.js';\r\nimport { appendAuditLine, pruneAuditFile } from '../core/audit-log.js';\r\nimport { loadEncryptedText } from '../vault/vault.js';\r\nimport { loadPolicy } from '../config/load.js';\r\nimport {\r\n addSeed,\r\n archiveSeedById,\r\n gcPool,\r\n loadPool,\r\n activeSeeds,\r\n archivedSeeds,\r\n seedsFilePath,\r\n surfaceSeed,\r\n} from '../seeds/pool.js';\r\nimport {\r\n appendEntry,\r\n ledgerFilePath,\r\n markDone,\r\n readLedger,\r\n scanPending,\r\n} from '../ledger/ledger.js';\r\nimport {\r\n adviseWander,\r\n browseStatePath,\r\n browseStatus,\r\n checkWatchlist,\r\n completeWander,\r\n loadInterests,\r\n loadWatchlist,\r\n} from '../browse/browse.js';\r\nimport { ensureRegistered, sendNewMessageHint } from '../notify/notify.js';\r\nimport {\r\n loadProfile,\r\n profileFilePath,\r\n verifyProfile,\r\n rebuildProfile,\r\n} from '../profile/store.js';\r\nimport { loadProfileSchema } from '../profile/schema.js';\r\nimport { planBurn, executeBurn } from '../vault/burn-list.js';\r\nimport { writeText } from '../vault/vault.js';\r\nimport {\r\n BUNDLED_PRESET_ID,\r\n conventionalUserPresetRoot,\r\n describeInstall,\r\n installBundledPreset,\r\n presetStatus,\r\n} from '../core/preset-install.js';\r\n\r\nfunction usage(): string {\r\n return [\r\n 'usage: heartbeat <command> [args]',\r\n '',\r\n 'commands:',\r\n ' status workspace paths + policy summary',\r\n ' seeds add <text> [--tag t] [--source s] [--topic x] [--confidence n]',\r\n ' seeds list [--archived] list active (or archived) seeds',\r\n ' seeds surface <id> count a surfacing (rule 1 accounting)',\r\n ' seeds archive <id> deliberate retirement (completed)',\r\n ' seeds gc run deterministic eviction rules 1-3',\r\n ' seeds stats pool status JSON',\r\n ' ledger add <text> register an open item',\r\n ' ledger list [--pending] list entries',\r\n ' ledger done <id|substring> mark an entry done',\r\n ' ledger open open ledger.md in the default editor',\r\n ' logs cleanup [--dry-run] apply log retention now',\r\n ' browse status browse state summary (watch + wander)',\r\n ' browse dry wander adjudication with forced noon window',\r\n ' browse watch run watchlist check now (network)',\r\n ' browse done <focus> CODE-side registration after a wander visit',\r\n ' bind list list session bindings (D13)',\r\n ' bind add <sessionId> [--observe] bind a session (deliver by default)',\r\n ' bind remove <sessionId> unbind a session',\r\n ' sessions list enumerate persisted sessions (ids)',\r\n ' notify check|register|send toast channel (D12: hint only, no body)',\r\n ' profile list [--all] current valid (or all incl. expired) entries',\r\n ' profile export decrypted Markdown export to data/exports/',\r\n ' profile verify journal replay vs disk (report only)',\r\n ' profile rebuild [--check] rebuild materialized view from journal',\r\n ' profile wipe wipe profile data (asks --yes)',\r\n ' burn [--yes] [--all] shred runtime data (settings kept unless --all)',\r\n ' preset status bundled agent preset: target dir + installed?',\r\n ' preset install [--force] install the bundled preset (never overwrites unless --force)',\r\n ].join('\\n');\r\n}\r\n\r\nfunction readStdinText(): string {\r\n try {\r\n return fs.readFileSync(0, 'utf8').trim();\r\n } catch {\r\n return '';\r\n }\r\n}\r\n\r\nfunction flag(argv: string[], name: string): string | undefined {\r\n const i = argv.indexOf(name);\r\n return i > -1 ? argv[i + 1] : undefined;\r\n}\r\n\r\nexport async function main(argv: string[]): Promise<number> {\r\n const [cmd, sub, ...rest] = argv;\r\n if (!cmd || cmd === 'help' || cmd === '--help') {\r\n console.log(usage());\r\n return 0;\r\n }\r\n const paths = initWorkspace();\r\n const guard = createPathGuard(paths.dataDir);\r\n const policy = loadPolicy(guard, paths.configDir, paths.settingsDir);\r\n const seedsFile = seedsFilePath(paths.dataDir);\r\n const ledgerFile = ledgerFilePath(paths.dataDir);\r\n const decisionLog = path.join(paths.logsDir, 'heartbeat.jsonl');\r\n\r\n switch (cmd) {\r\n case 'status': {\r\n console.log(JSON.stringify({\r\n dataDir: paths.dataDir,\r\n heartbeatIntervalMin: policy.heartbeat.intervalMin,\r\n maxDailySend: policy.gate.maxDailySend,\r\n seedsMaxActive: policy.seeds.maxActive,\r\n psyEnabled: policy.profile.psyEnabled,\r\n }, null, 2));\r\n return 0;\r\n }\r\n\r\n case 'seeds': {\r\n switch (sub) {\r\n case 'add': {\r\n let text = rest[0]?.trim() ?? '';\r\n if (text === '-') text = readStdinText();\r\n if (!text) {\r\n console.error('usage: seeds add <text|-> [--tag t] [--source s] [--topic x] [--confidence n]');\r\n return 1;\r\n }\r\n const result = addSeed(guard, seedsFile, policy, {\r\n text,\r\n tag: flag(rest, '--tag') as never,\r\n source: flag(rest, '--source') as never,\r\n topic: flag(rest, '--topic'),\r\n confidence: flag(rest, '--confidence') ? Number(flag(rest, '--confidence')) : undefined,\r\n });\r\n if (result.kind === 'duplicate') {\r\n console.log(`DUPLICATE: active seed ${result.seed.id} has the same text`);\r\n return 0;\r\n }\r\n console.log(`${result.kind.toUpperCase()} ${result.seed.id}` +\r\n ` (${activeSeeds(loadPool(guard, seedsFile)).length}/${policy.seeds.maxActive})` +\r\n (result.evicted ? ` [evicted ${result.evicted.id}: ${result.evicted.retireReason}]` : ''));\r\n return 0;\r\n }\r\n case 'list': {\r\n const db = loadPool(guard, seedsFile);\r\n const items = rest.includes('--archived') ? archivedSeeds(db) : activeSeeds(db);\r\n for (const s of items) {\r\n const ageDays = Math.floor((Date.now() - Date.parse(s.bornAt)) / 86_400_000);\r\n console.log(`${s.id} [${s.tag}/${s.source}] d${ageDays} used:${s.used}` +\r\n `${s.protected ? ' *' : ''} ${s.text.slice(0, 60)}`);\r\n }\r\n if (items.length === 0) console.log('(empty)');\r\n return 0;\r\n }\r\n case 'surface': {\r\n const s = surfaceSeed(guard, seedsFile, policy, rest[0] ?? '');\r\n if (!s) {\r\n console.log('NOT_FOUND');\r\n return 1;\r\n }\r\n console.log(`SURFACED ${s.id} used:${s.used}${s.status === 'archived' ? ' -> archived (consumed)' : ''}`);\r\n return 0;\r\n }\r\n case 'archive': {\r\n const s = archiveSeedById(guard, seedsFile, rest[0] ?? '');\r\n if (!s) {\r\n console.log('NOT_FOUND');\r\n return 1;\r\n }\r\n console.log(`ARCHIVED ${s.id}`);\r\n return 0;\r\n }\r\n case 'gc': {\r\n const report = gcPool(guard, seedsFile, policy);\r\n console.log(`GC consumed:${report.consumed} expired:${report.expired} cold_bench:${report.coldBench}` +\r\n ` -> active ${report.activeAfter}/${policy.seeds.maxActive}`);\r\n return 0;\r\n }\r\n case 'stats': {\r\n const db = loadPool(guard, seedsFile);\r\n console.log(JSON.stringify({\r\n active: activeSeeds(db).length,\r\n archived: archivedSeeds(db).length,\r\n cap: policy.seeds.maxActive,\r\n seq: db.seq,\r\n }, null, 2));\r\n return 0;\r\n }\r\n default:\r\n console.error(`unknown seeds subcommand: ${sub}`);\r\n return 1;\r\n }\r\n }\r\n\r\n case 'ledger': {\r\n switch (sub) {\r\n case 'add': {\r\n let text = rest.join(' ').trim();\r\n if (text === '-') text = readStdinText();\r\n if (!text) {\r\n console.error('usage: ledger add <text|->');\r\n return 1;\r\n }\r\n const e = appendEntry(guard, ledgerFile, text);\r\n console.log(`OPEN #${e.id} ${e.text.slice(0, 60)}`);\r\n return 0;\r\n }\r\n case 'list': {\r\n const { entries } = readLedger(guard, ledgerFile);\r\n const items = rest.includes('--pending') ? scanPending(guard, ledgerFile) : entries;\r\n for (const e of items) console.log(`${e.status === 'open' ? ' ' : 'x'} #${e.id} ${e.date} ${e.text.slice(0, 60)}`);\r\n if (items.length === 0) console.log('(empty)');\r\n return 0;\r\n }\r\n case 'done': {\r\n const key = rest.join(' ').trim();\r\n if (!key) {\r\n console.error('usage: ledger done <id|substring>');\r\n return 1;\r\n }\r\n const e = markDone(guard, ledgerFile, key);\r\n if (!e) {\r\n console.log('NOT_FOUND');\r\n return 1;\r\n }\r\n console.log(`DONE #${e.id}`);\r\n return 0;\r\n }\r\n case 'open': {\r\n const f = ledgerFile;\r\n if (!fs.existsSync(f)) {\r\n console.log(`(ledger will be created at ${f})`);\r\n }\r\n spawn('cmd', ['/c', 'start', '', f], { detached: true, stdio: 'ignore' }).unref();\r\n console.log(`opened ${f}`);\r\n return 0;\r\n }\r\n default:\r\n console.error(`unknown ledger subcommand: ${sub}`);\r\n return 1;\r\n }\r\n }\r\n\r\n case 'logs': {\r\n if (sub !== 'cleanup') {\r\n console.error('usage: logs cleanup [--dry-run]');\r\n return 1;\r\n }\r\n const dry = rest.includes('--dry-run');\r\n const envPulse = path.join(paths.logsDir, 'envpulse.jsonl');\r\n const cut1 = policy.retention.envPulseHours * 3600_000;\r\n const cut2 = policy.retention.decisionLogDays * 86_400_000;\r\n if (dry) {\r\n console.log(`(dry-run) would prune ${envPulse} to ${policy.retention.envPulseHours}h` +\r\n ` and ${decisionLog} to ${policy.retention.decisionLogDays}d`);\r\n return 0;\r\n }\r\n const a = pruneAuditFile(envPulse, cut1);\r\n const b = pruneAuditFile(decisionLog, cut2);\r\n appendAuditLine(decisionLog, { event: 'retention', pruned_envpulse: a, pruned_decision: b });\r\n console.log(`PRUNED envpulse:${a} decision:${b}`);\r\n return 0;\r\n }\r\n\r\n case 'browse': {\r\n switch (sub) {\r\n case 'status': {\r\n const st = browseStatus(guard, paths);\r\n const interests = loadInterests(paths);\r\n console.log(JSON.stringify({\r\n watchTargets: loadWatchlist(paths).targets?.length ?? 0,\r\n lastCheckAt: st.last_check_at ? new Date(st.last_check_at).toISOString() : null,\r\n lastWanderAt: st.wander.last_wander_at ? new Date(st.wander.last_wander_at).toISOString() : null,\r\n focusCount: st.wander.focusCount,\r\n interestCount: interests.interests?.length ?? 0,\r\n }, null, 2));\r\n return 0;\r\n }\r\n case 'dry': {\r\n const forced = new Date();\r\n forced.setHours(12, 0, 0, 0);\r\n const advice = adviseWander(guard, paths, policy, forced);\r\n console.log(JSON.stringify(advice, null, 2));\r\n return 0;\r\n }\r\n case 'watch': {\r\n const report = await checkWatchlist(guard, paths, { throttleOk: true });\r\n console.log(JSON.stringify({ checked: report.checked, updates: report.items.length, errors: report.errors }, null, 2));\r\n for (const item of report.items) console.log(`NEWS: ${item.text}`);\r\n return 0;\r\n }\r\n case 'done': {\r\n const focus = rest.join(' ').trim();\r\n if (!focus) {\r\n console.error('usage: browse done <focus>');\r\n return 1;\r\n }\r\n const r = completeWander(guard, paths, focus);\r\n console.log(JSON.stringify(r));\r\n return 0;\r\n }\r\n default:\r\n console.error(`unknown browse subcommand: ${sub}`);\r\n return 1;\r\n }\r\n }\r\n\r\n case 'notify': {\r\n switch (sub) {\r\n case 'check':\r\n console.log(ensureRegistered(paths) ? 'REGISTERED: yes' : 'REGISTERED: no');\r\n return 0;\r\n case 'register':\r\n ensureRegistered(paths);\r\n console.log('register attempted');\r\n return 0;\r\n case 'send':\r\n console.log(sendNewMessageHint(paths) ? 'SENT' : 'FAILED');\r\n return 0;\r\n default:\r\n console.error('usage: notify check|register|send');\r\n return 1;\r\n }\r\n }\r\n\r\n case 'profile': {\r\n const doc = loadProfile(guard, profileFilePath(paths.dataDir));\r\n const all = rest.includes('--all');\r\n switch (sub) {\r\n case 'list': {\r\n let n = 0;\r\n for (const p of ['interest', 'projects', 'comm', 'psy'] as const) {\r\n for (const e of doc.partitions[p]!.entries) {\r\n if (!all && e.validTo !== null) continue;\r\n n += 1;\r\n console.log(`${e.id} [${e.partition}/${e.topic}/${e.subTopic}] ${e.temporal}` +\r\n ` conf=${e.confidence.toFixed(2)}${e.lowActivity ? ' 久未验证' : ''}${e.validTo ? ' [失效]' : ''}: ${e.content.slice(0, 60)}`);\r\n }\r\n }\r\n if (n === 0) console.log('(empty)');\r\n return 0;\r\n }\r\n case 'export': {\r\n const lines = [`# 画像导出 ${new Date().toISOString()}`, ''];\r\n for (const p of ['interest', 'projects', 'comm', 'psy'] as const) {\r\n lines.push(`## ${p}`);\r\n for (const e of doc.partitions[p]!.entries) {\r\n if (e.validTo !== null) continue;\r\n lines.push(`- [${e.topic}/${e.subTopic}] ${e.content} (conf ${e.confidence.toFixed(2)}, ${e.temporal})`);\r\n }\r\n }\r\n const out = path.join(paths.exportsDir, `profile-export-${Date.now()}.md`);\r\n writeText(guard, out, lines.join('\\n') + '\\n');\r\n console.log(`EXPORTED: ${out}`);\r\n return 0;\r\n }\r\n case 'verify': {\r\n const r = verifyProfile(guard, paths.dataDir);\r\n console.log(JSON.stringify(r, null, 2));\r\n return r.ok ? 0 : 1;\r\n }\r\n case 'rebuild': {\r\n const r = rebuildProfile(guard, paths.dataDir, { check: rest.includes('--check') });\r\n console.log(JSON.stringify(r, null, 2));\r\n return r.ok ? 0 : 1;\r\n }\r\n case 'wipe': {\r\n if (!rest.includes('--yes')) {\r\n console.log('REFUSED: add --yes to wipe profile data (profile.json/inbox/journal)');\r\n return 1;\r\n }\r\n for (const f of ['profile.json', 'profile_inbox.jsonl', 'profile_journal.jsonl']) {\r\n const abs = guard.assert(path.join(paths.dataDir, f));\r\n if (fs.existsSync(abs)) fs.rmSync(abs, { force: true });\r\n }\r\n console.log('WIPED (settings preserved; use burn for full shredding)');\r\n return 0;\r\n }\r\n default:\r\n console.error(`unknown profile subcommand: ${sub}`);\r\n return 1;\r\n }\r\n }\r\n\r\n case 'burn': {\r\n const yes = rest.includes('--yes');\r\n const all = rest.includes('--all');\r\n const plan = planBurn(guard, paths, all);\r\n console.log('预演(不会执行):' );\r\n for (const p of plan) console.log(` [${p.exists ? '存在' : '无 '}] ${p.target.file ?? p.target.dir} ${p.target.note}`);\r\n if (!yes) {\r\n console.log('\\n此操作会让心跳 agent 失忆。确认执行请加 --yes(' + (all ? '含 --all 连用户设定' : '用户设定保留') + ')');\r\n return 0;\r\n }\r\n const result = executeBurn(guard, paths, { all });\r\n console.log(`BURNED: ${result.burned.length} 项;MISSING: ${result.missing.length} 项`);\r\n return 0;\r\n }\r\n\r\n case 'sessions': {\r\n // Read-only enumeration of the host's persisted sessions (ids from the\r\n // on-disk store; titles live server-side and are not listed here).\r\n const root = path.join(os.homedir(), '.dsh', 'sessions');\r\n let found = 0;\r\n if (fs.existsSync(root)) {\r\n let own: string | null = null;\r\n try {\r\n own = (JSON.parse(loadEncryptedText(guard, path.join(paths.dataDir, 'gate.json')) ?? '{}') as { sessionId?: string }).sessionId ?? null;\r\n } catch { /* gate.json absent or unreadable */ }\r\n for (const slug of fs.readdirSync(root)) {\r\n for (const id of fs.readdirSync(path.join(root, slug))) {\r\n found += 1;\r\n const mark = id === own ? ' ← 心跳正身' : '';\r\n console.log(`${id} [${slug}]${mark}`);\r\n }\r\n }\r\n }\r\n if (found === 0) console.log('(no persisted sessions found)');\r\n return 0;\r\n }\r\n\r\n case 'bind': {\r\n const { loadBindings, addBinding, removeBinding, bindingsFilePath } = await import('../core/bindings.js');\r\n switch (sub) {\r\n case 'list': {\r\n const data = loadBindings(guard, paths.settingsDir);\r\n let own: string | null = null;\r\n try {\r\n own = (JSON.parse(loadEncryptedText(guard, path.join(paths.dataDir, 'gate.json')) ?? '{}') as { sessionId?: string }).sessionId ?? null;\r\n } catch { /* absent */ }\r\n if (own) console.log(`心跳正身: ${own}(决策轮次发生地;bind remove 它 = 重置正身)`);\r\n for (const b of data.bindings) {\r\n console.log(`${b.sessionId} deliver:${b.deliver ? '√' : '×'} observe:${b.observe ? '√' : '×'}`);\r\n }\r\n if (data.bindings.length === 0 && !own) console.log('(no bindings — expressions stay in the dedicated heartbeat session)');\r\n return 0;\r\n }\r\n case 'add': {\r\n const id = rest[0];\r\n if (!id || !id.startsWith('session-')) {\r\n console.error('usage: bind add <sessionId> [--observe] [--no-deliver] (see: sessions list)');\r\n return 1;\r\n }\r\n const observe = rest.includes('--observe') || rest.includes('--observe-only');\r\n const deliver = !rest.includes('--no-deliver') && !rest.includes('--observe-only');\r\n const b = addBinding(guard, paths.settingsDir, id, { deliver, observe });\r\n console.log(`BOUND ${b.sessionId} deliver:${b.deliver} observe:${b.observe}`);\r\n return 0;\r\n }\r\n case 'remove': {\r\n const id = rest[0];\r\n if (!id) {\r\n console.error('usage: bind remove <sessionId>');\r\n return 1;\r\n }\r\n console.log(removeBinding(guard, paths.settingsDir, id) ? `UNBOUND ${id}` : 'NOT_FOUND');\r\n // Unbinding the HOME session resets it: the next beat creates a\r\n // fresh dedicated session (the old one goes quiet after restart).\r\n try {\r\n const state = JSON.parse(loadEncryptedText(guard, path.join(paths.dataDir, 'gate.json')) ?? '{}') as { sessionId?: string };\r\n if (state.sessionId === id) {\r\n fs.rmSync(guard.assert(path.join(paths.dataDir, 'gate.json')), { force: true });\r\n console.log('注意:这是心跳正身会话。已重置——下次心跳将创建新的正身会话(旧会话不再有心跳)');\r\n appendAuditLine(paths.logsDir + '/heartbeat.jsonl', { event: 'home_reset', oldSessionId: id });\r\n }\r\n } catch { /* gate.json absent: nothing to reset */ }\r\n return 0;\r\n }\r\n default:\r\n console.error('usage: bind list | add <sessionId> | remove <sessionId>');\r\n return 1;\r\n }\r\n }\r\n\r\n case 'preset': {\r\n const id = flag(argv, '--id') ?? BUNDLED_PRESET_ID;\r\n // The plugin installs into the roster's own user root; the CLI has no\r\n // roster, so it reports/uses the conventional one ($DSH_HOME or ~/.dsh).\r\n const root = conventionalUserPresetRoot();\r\n const status = presetStatus(import.meta.url, id, root);\r\n if (sub === undefined || sub === 'status') {\r\n console.log(`preset id : ${status.id}`);\r\n console.log(`installed : ${status.installed ? 'yes' : 'no'}`);\r\n console.log(`target dir : ${status.dir}`);\r\n console.log(`bundled at : ${status.bundledDir ?? '(not found next to the plugin)'}`);\r\n if (status.installed) {\r\n console.log(\r\n `composition : ${status.compositionMatches ? 'matches the bundled template' : 'differs from the bundled template (hand-edited, or an older version)'}`,\r\n );\r\n }\r\n if (!status.installed) {\r\n console.log('hint: the plugin installs this itself on the next DSH start (installPreset=true, default);');\r\n console.log(' or run `preset install` now.');\r\n }\r\n return status.installed ? 0 : 1;\r\n }\r\n if (sub === 'install') {\r\n const result = installBundledPreset({\r\n moduleUrl: import.meta.url,\r\n id,\r\n root,\r\n force: rest.includes('--force'),\r\n });\r\n console.log(describeInstall(result));\r\n return result.action === 'error' ? 1 : 0;\r\n }\r\n console.error('usage: preset status | install [--force] [--id <presetId>]');\r\n return 1;\r\n }\r\n\r\n default:\r\n console.error(`unknown command: ${cmd}`);\r\n console.log(usage());\r\n return 1;\r\n }\r\n}\r\n\r\nif (process.argv[1] && import.meta.url === new URL(`file:///${process.argv[1].replace(/\\\\/g, '/')}`).href) {\r\n // Direct execution guard; the CLI is also importable for tests.\r\n void main(process.argv.slice(2)).then((code) => { process.exitCode = code; });\r\n}\r\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 /** 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 { 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 { dir: 'tmp', note: '解锁临时文件(崩溃残留的解密明文是最该烧的东西)' },\n { dir: 'logs', note: '审计与决策日志' },\n { dir: 'exports', note: '导出产物' },\n];\n\nconst SETTINGS_DIR = 'settings'; // excluded unless --all\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!;\n if (!all && rel === SETTINGS_DIR) continue;\n const abs = path.join(paths.dataDir, rel);\n let exists = false;\n try {\n exists = fs.existsSync(guard.assert(abs));\n } catch {\n exists = false;\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 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.\r\n// Run: node dist/cli/index.js <command> [args] (or via tsx in dev)\r\n\r\nimport { spawn } from 'node:child_process';\r\nimport fs from 'node:fs';\r\nimport os from 'node:os';\r\nimport path from 'node:path';\r\nimport { initWorkspace, workspace } from '../core/paths.js';\r\nimport { createPathGuard } from '../core/path-guard.js';\r\nimport { appendAuditLine, pruneAuditFile } from '../core/audit-log.js';\r\nimport { loadEncryptedText } from '../vault/vault.js';\r\nimport { loadPolicy } from '../config/load.js';\r\nimport {\r\n addSeed,\r\n archiveSeedById,\r\n gcPool,\r\n loadPool,\r\n activeSeeds,\r\n archivedSeeds,\r\n seedsFilePath,\r\n surfaceSeed,\r\n} from '../seeds/pool.js';\r\nimport {\r\n appendEntry,\r\n ledgerFilePath,\r\n markDone,\r\n readLedger,\r\n scanPending,\r\n} from '../ledger/ledger.js';\r\nimport {\r\n adviseWander,\r\n browseStatePath,\r\n browseStatus,\r\n checkWatchlist,\r\n completeWander,\r\n loadInterests,\r\n loadWatchlist,\r\n} from '../browse/browse.js';\r\nimport { ensureRegistered, sendNewMessageHint } from '../notify/notify.js';\r\nimport {\r\n loadProfile,\r\n profileFilePath,\r\n verifyProfile,\r\n rebuildProfile,\r\n} from '../profile/store.js';\r\nimport { loadProfileSchema } from '../profile/schema.js';\r\nimport { planBurn, executeBurn } from '../vault/burn-list.js';\r\nimport {\r\n collectMigrationEntries,\r\n encryptContainer,\r\n decryptContainer,\r\n applyMigrationEntries,\r\n} from '../vault/migrate.js';\r\nimport { listWeeklyReports, readWeeklyReport, weeklyDirPath } from '../weekly/report.js';\r\nimport { writeText } from '../vault/vault.js';\r\nimport {\r\n BUNDLED_PRESET_ID,\r\n conventionalUserPresetRoot,\r\n describeInstall,\r\n installBundledPreset,\r\n presetStatus,\r\n} from '../core/preset-install.js';\r\n\r\nfunction usage(): string {\r\n return [\r\n 'usage: heartbeat <command> [args]',\r\n '',\r\n 'commands:',\r\n ' status workspace paths + policy summary',\r\n ' seeds add <text> [--tag t] [--source s] [--topic x] [--confidence n]',\r\n ' seeds list [--archived] list active (or archived) seeds',\r\n ' seeds surface <id> count a surfacing (rule 1 accounting)',\r\n ' seeds archive <id> deliberate retirement (completed)',\r\n ' seeds gc run deterministic eviction rules 1-3',\r\n ' seeds stats pool status JSON',\r\n ' ledger add <text> register an open item',\r\n ' ledger list [--pending] list entries',\r\n ' ledger done <id|substring> mark an entry done',\r\n ' ledger open open ledger.md in the default editor',\r\n ' logs cleanup [--dry-run] apply log retention now',\r\n ' browse status browse state summary (watch + wander)',\r\n ' browse dry wander adjudication with forced noon window',\r\n ' browse watch run watchlist check now (network)',\r\n ' browse done <focus> CODE-side registration after a wander visit',\r\n ' bind list list session bindings (D13)',\r\n ' bind add <sessionId> [--observe] bind a session (deliver by default)',\r\n ' bind remove <sessionId> unbind a session',\r\n ' sessions list enumerate persisted sessions (ids)',\r\n ' notify check|register|send toast channel (D12: hint only, no body)',\r\n ' profile list [--all] current valid (or all incl. expired) entries',\r\n ' profile export decrypted Markdown export to data/exports/',\r\n ' profile verify journal replay vs disk (report only)',\r\n ' profile rebuild [--check] rebuild materialized view from journal',\r\n ' profile snapshot [--force] fold the journal into a snapshot + archive shard',\r\n ' profile wipe wipe profile data (asks --yes)',\r\n ' weekly list list generated weekly reports',\r\n ' weekly show [file] print a report (default: newest)',\r\n ' migrate export [file] pack memory files into a passphrase container (passphrase: 2 stdin lines)',\r\n ' migrate import <file> restore a container into this workspace (passphrase: 1 stdin line)',\r\n ' burn [--yes] [--all] shred runtime data (settings kept unless --all)',\r\n ' preset status bundled agent preset: target dir + installed?',\r\n ' preset install [--force] install the bundled preset (never overwrites unless --force)',\r\n ].join('\\n');\r\n}\r\n\r\nfunction readStdinText(): string {\r\n try {\r\n return fs.readFileSync(0, 'utf8').trim();\r\n } catch {\r\n return '';\r\n }\r\n}\r\n\r\nfunction flag(argv: string[], name: string): string | undefined {\r\n const i = argv.indexOf(name);\r\n return i > -1 ? argv[i + 1] : undefined;\r\n}\r\n\r\n/** Read N lines from stdin (passphrase prompts for migrate). */\r\nasync function readLines(prompts: string[]): Promise<string[]> {\r\n const readline = await import('node:readline/promises');\r\n const it = readline.createInterface({ input: process.stdin });\r\n const out: string[] = [];\r\n for (const p of prompts) out.push((await it.question(p)).trim());\r\n it.close();\r\n return out;\r\n}\r\n\r\nexport async function main(argv: string[]): Promise<number> {\r\n const [cmd, sub, ...rest] = argv;\r\n if (!cmd || cmd === 'help' || cmd === '--help') {\r\n console.log(usage());\r\n return 0;\r\n }\r\n const paths = initWorkspace();\r\n const guard = createPathGuard(paths.dataDir);\r\n const policy = loadPolicy(guard, paths.configDir, paths.settingsDir);\r\n const seedsFile = seedsFilePath(paths.dataDir);\r\n const ledgerFile = ledgerFilePath(paths.dataDir);\r\n const decisionLog = path.join(paths.logsDir, 'heartbeat.jsonl');\r\n /** Seed lifecycle audit (v1.9.0): CLI edits land in the same log as the beat's. */\r\n const seedAudit = (entry: Record<string, unknown>): void => {\r\n try {\r\n appendAuditLine(decisionLog, entry);\r\n } catch { /* audit must never break the command */ }\r\n };\r\n\r\n switch (cmd) {\r\n case 'status': {\r\n console.log(JSON.stringify({\r\n dataDir: paths.dataDir,\r\n heartbeatIntervalMin: policy.heartbeat.intervalMin,\r\n maxDailySend: policy.gate.maxDailySend,\r\n seedsMaxActive: policy.seeds.maxActive,\r\n psyEnabled: policy.profile.psyEnabled,\r\n }, null, 2));\r\n return 0;\r\n }\r\n\r\n case 'seeds': {\r\n switch (sub) {\r\n case 'add': {\r\n let text = rest[0]?.trim() ?? '';\r\n if (text === '-') text = readStdinText();\r\n if (!text) {\r\n console.error('usage: seeds add <text|-> [--tag t] [--source s] [--topic x] [--confidence n]');\r\n return 1;\r\n }\r\n const result = addSeed(guard, seedsFile, policy, {\r\n text,\r\n tag: flag(rest, '--tag') as never,\r\n source: flag(rest, '--source') as never,\r\n topic: flag(rest, '--topic'),\r\n confidence: flag(rest, '--confidence') ? Number(flag(rest, '--confidence')) : undefined,\r\n }, Date.now(), seedAudit);\r\n if (result.kind === 'duplicate') {\r\n console.log(`DUPLICATE: active seed ${result.seed.id} has the same text`);\r\n return 0;\r\n }\r\n console.log(`${result.kind.toUpperCase()} ${result.seed.id}` +\r\n ` (${activeSeeds(loadPool(guard, seedsFile)).length}/${policy.seeds.maxActive})` +\r\n (result.evicted ? ` [evicted ${result.evicted.id}: ${result.evicted.retireReason}]` : ''));\r\n return 0;\r\n }\r\n case 'list': {\r\n const db = loadPool(guard, seedsFile);\r\n const items = rest.includes('--archived') ? archivedSeeds(db) : activeSeeds(db);\r\n for (const s of items) {\r\n const ageDays = Math.floor((Date.now() - Date.parse(s.bornAt)) / 86_400_000);\r\n console.log(`${s.id} [${s.tag}/${s.source}] d${ageDays} used:${s.used}` +\r\n `${s.protected ? ' *' : ''} ${s.text.slice(0, 60)}`);\r\n }\r\n if (items.length === 0) console.log('(empty)');\r\n return 0;\r\n }\r\n case 'surface': {\r\n const s = surfaceSeed(guard, seedsFile, policy, rest[0] ?? '', Date.now(), seedAudit);\r\n if (!s) {\r\n console.log('NOT_FOUND');\r\n return 1;\r\n }\r\n console.log(`SURFACED ${s.id} used:${s.used}${s.status === 'archived' ? ' -> archived (consumed)' : ''}`);\r\n return 0;\r\n }\r\n case 'archive': {\r\n const s = archiveSeedById(guard, seedsFile, rest[0] ?? '', 'completed', Date.now(), seedAudit);\r\n if (!s) {\r\n console.log('NOT_FOUND');\r\n return 1;\r\n }\r\n console.log(`ARCHIVED ${s.id}`);\r\n return 0;\r\n }\r\n case 'gc': {\r\n const report = gcPool(guard, seedsFile, policy, Date.now(), seedAudit);\r\n console.log(`GC consumed:${report.consumed} expired:${report.expired} cold_bench:${report.coldBench}` +\r\n ` archive_trimmed:${report.archiveTrimmed} -> active ${report.activeAfter}/${policy.seeds.maxActive}` +\r\n ` archive ${archivedSeeds(loadPool(guard, seedsFile)).length}/${policy.seeds.archiveCap}`);\r\n return 0;\r\n }\r\n case 'stats': {\r\n const db = loadPool(guard, seedsFile);\r\n console.log(JSON.stringify({\r\n active: activeSeeds(db).length,\r\n archived: archivedSeeds(db).length,\r\n cap: policy.seeds.maxActive,\r\n seq: db.seq,\r\n }, null, 2));\r\n return 0;\r\n }\r\n default:\r\n console.error(`unknown seeds subcommand: ${sub}`);\r\n return 1;\r\n }\r\n }\r\n\r\n case 'ledger': {\r\n switch (sub) {\r\n case 'add': {\r\n let text = rest.join(' ').trim();\r\n if (text === '-') text = readStdinText();\r\n if (!text) {\r\n console.error('usage: ledger add <text|->');\r\n return 1;\r\n }\r\n const e = appendEntry(guard, ledgerFile, text);\r\n console.log(`OPEN #${e.id} ${e.text.slice(0, 60)}`);\r\n return 0;\r\n }\r\n case 'list': {\r\n const { entries } = readLedger(guard, ledgerFile);\r\n const items = rest.includes('--pending') ? scanPending(guard, ledgerFile) : entries;\r\n for (const e of items) console.log(`${e.status === 'open' ? ' ' : 'x'} #${e.id} ${e.date} ${e.text.slice(0, 60)}`);\r\n if (items.length === 0) console.log('(empty)');\r\n return 0;\r\n }\r\n case 'done': {\r\n const key = rest.join(' ').trim();\r\n if (!key) {\r\n console.error('usage: ledger done <id|substring>');\r\n return 1;\r\n }\r\n const e = markDone(guard, ledgerFile, key);\r\n if (!e) {\r\n console.log('NOT_FOUND');\r\n return 1;\r\n }\r\n console.log(`DONE #${e.id}`);\r\n return 0;\r\n }\r\n case 'open': {\r\n const f = ledgerFile;\r\n if (!fs.existsSync(f)) {\r\n console.log(`(ledger will be created at ${f})`);\r\n }\r\n spawn('cmd', ['/c', 'start', '', f], { detached: true, stdio: 'ignore' }).unref();\r\n console.log(`opened ${f}`);\r\n return 0;\r\n }\r\n default:\r\n console.error(`unknown ledger subcommand: ${sub}`);\r\n return 1;\r\n }\r\n }\r\n\r\n case 'weekly': {\r\n const reports = listWeeklyReports(guard, paths.dataDir);\r\n if (sub === 'list' || sub === undefined) {\r\n if (reports.length === 0) console.log('(no reports yet — heartbeat generates one every 7 days)');\r\n for (const r of reports) console.log(`${r.file} ${r.start.slice(0, 10)} ~ ${r.end.slice(0, 10)} [${r.source}]`);\r\n return 0;\r\n }\r\n if (sub === 'show') {\r\n const file = rest[0] ?? reports[0]?.file;\r\n if (!file) {\r\n console.log('(no reports yet)');\r\n return 1;\r\n }\r\n const rep = readWeeklyReport(guard, paths.dataDir, file);\r\n if (!rep) {\r\n console.error(`no such report: ${file} (see: weekly list; files live in ${weeklyDirPath(paths.dataDir)})`);\r\n return 1;\r\n }\r\n console.log(`# ${rep.start.slice(0, 10)} ~ ${rep.end.slice(0, 10)} [${rep.source}]`);\r\n console.log(rep.text);\r\n return 0;\r\n }\r\n console.error(`unknown weekly subcommand: ${sub}`);\r\n return 1;\r\n }\r\n\r\n case 'logs': {\r\n if (sub !== 'cleanup') {\r\n console.error('usage: logs cleanup [--dry-run]');\r\n return 1;\r\n }\r\n const dry = rest.includes('--dry-run');\r\n const envPulse = path.join(paths.logsDir, 'envpulse.jsonl');\r\n const cut1 = policy.retention.envPulseHours * 3600_000;\r\n const cut2 = policy.retention.decisionLogDays * 86_400_000;\r\n if (dry) {\r\n console.log(`(dry-run) would prune ${envPulse} to ${policy.retention.envPulseHours}h` +\r\n ` and ${decisionLog} to ${policy.retention.decisionLogDays}d`);\r\n return 0;\r\n }\r\n const a = pruneAuditFile(envPulse, cut1);\r\n const b = pruneAuditFile(decisionLog, cut2);\r\n appendAuditLine(decisionLog, { event: 'retention', pruned_envpulse: a, pruned_decision: b });\r\n console.log(`PRUNED envpulse:${a} decision:${b}`);\r\n return 0;\r\n }\r\n\r\n case 'browse': {\r\n switch (sub) {\r\n case 'status': {\r\n const st = browseStatus(guard, paths);\r\n const interests = loadInterests(paths);\r\n console.log(JSON.stringify({\r\n watchTargets: loadWatchlist(paths).targets?.length ?? 0,\r\n lastCheckAt: st.last_check_at ? new Date(st.last_check_at).toISOString() : null,\r\n lastWanderAt: st.wander.last_wander_at ? new Date(st.wander.last_wander_at).toISOString() : null,\r\n focusCount: st.wander.focusCount,\r\n interestCount: interests.interests?.length ?? 0,\r\n }, null, 2));\r\n return 0;\r\n }\r\n case 'dry': {\r\n const forced = new Date();\r\n forced.setHours(12, 0, 0, 0);\r\n const advice = adviseWander(guard, paths, policy, forced);\r\n console.log(JSON.stringify(advice, null, 2));\r\n return 0;\r\n }\r\n case 'watch': {\r\n const report = await checkWatchlist(guard, paths, { throttleOk: true });\r\n console.log(JSON.stringify({ checked: report.checked, updates: report.items.length, errors: report.errors }, null, 2));\r\n for (const item of report.items) console.log(`NEWS: ${item.text}`);\r\n return 0;\r\n }\r\n case 'done': {\r\n const focus = rest.join(' ').trim();\r\n if (!focus) {\r\n console.error('usage: browse done <focus>');\r\n return 1;\r\n }\r\n const r = completeWander(guard, paths, focus);\r\n console.log(JSON.stringify(r));\r\n return 0;\r\n }\r\n default:\r\n console.error(`unknown browse subcommand: ${sub}`);\r\n return 1;\r\n }\r\n }\r\n\r\n case 'notify': {\r\n switch (sub) {\r\n case 'check':\r\n console.log(ensureRegistered(paths) ? 'REGISTERED: yes' : 'REGISTERED: no');\r\n return 0;\r\n case 'register':\r\n ensureRegistered(paths);\r\n console.log('register attempted');\r\n return 0;\r\n case 'send':\r\n console.log(sendNewMessageHint(paths) ? 'SENT' : 'FAILED');\r\n return 0;\r\n default:\r\n console.error('usage: notify check|register|send');\r\n return 1;\r\n }\r\n }\r\n\r\n case 'profile': {\r\n const doc = loadProfile(guard, profileFilePath(paths.dataDir));\r\n const all = rest.includes('--all');\r\n switch (sub) {\r\n case 'list': {\r\n let n = 0;\r\n for (const p of ['interest', 'projects', 'comm', 'psy'] as const) {\r\n for (const e of doc.partitions[p]!.entries) {\r\n if (!all && e.validTo !== null) continue;\r\n n += 1;\r\n console.log(`${e.id} [${e.partition}/${e.topic}/${e.subTopic}] ${e.temporal}` +\r\n ` conf=${e.confidence.toFixed(2)}${e.lowActivity ? ' 久未验证' : ''}${e.validTo ? ' [失效]' : ''}: ${e.content.slice(0, 60)}`);\r\n }\r\n }\r\n if (n === 0) console.log('(empty)');\r\n return 0;\r\n }\r\n case 'export': {\r\n const lines = [`# 画像导出 ${new Date().toISOString()}`, ''];\r\n for (const p of ['interest', 'projects', 'comm', 'psy'] as const) {\r\n lines.push(`## ${p}`);\r\n for (const e of doc.partitions[p]!.entries) {\r\n if (e.validTo !== null) continue;\r\n lines.push(`- [${e.topic}/${e.subTopic}] ${e.content} (conf ${e.confidence.toFixed(2)}, ${e.temporal})`);\r\n }\r\n }\r\n const out = path.join(paths.exportsDir, `profile-export-${Date.now()}.md`);\r\n writeText(guard, out, lines.join('\\n') + '\\n');\r\n console.log(`EXPORTED: ${out}`);\r\n return 0;\r\n }\r\n case 'verify': {\r\n const r = verifyProfile(guard, paths.dataDir);\r\n console.log(JSON.stringify(r, null, 2));\r\n return r.ok ? 0 : 1;\r\n }\r\n case 'rebuild': {\r\n const r = rebuildProfile(guard, paths.dataDir, { check: rest.includes('--check') });\r\n console.log(JSON.stringify(r, null, 2));\r\n return r.ok ? 0 : 1;\r\n }\r\n case 'wipe': {\r\n if (!rest.includes('--yes')) {\r\n console.log('REFUSED: add --yes to wipe profile data (profile.json/inbox/journal)');\r\n return 1;\r\n }\r\n for (const f of ['profile.json', 'profile_inbox.jsonl', 'profile_journal.jsonl']) {\r\n const abs = guard.assert(path.join(paths.dataDir, f));\r\n if (fs.existsSync(abs)) fs.rmSync(abs, { force: true });\r\n }\r\n console.log('WIPED (settings preserved; use burn for full shredding)');\r\n return 0;\r\n }\r\n case 'snapshot': {\r\n const { snapshotDue, snapshotProfile, SNAPSHOT_THRESHOLD } = await import('../profile/snapshot.js');\r\n const { needed, lines } = snapshotDue(guard, paths.dataDir);\r\n console.log(`journal ${lines} 条(阈值 ${SNAPSHOT_THRESHOLD})`);\r\n if (!needed && !rest.includes('--force')) {\r\n console.log('未到阈值,未执行(加 --force 强制折叠)。');\r\n return 0;\r\n }\r\n const report = snapshotProfile(guard, paths.dataDir);\r\n if (!report.ok) {\r\n console.log(`未执行:${report.reason}`);\r\n return 0;\r\n }\r\n console.log(`已折叠 ${report.folded} 条 → 快照(baseline ${report.baselineTs}),归档 ${report.archiveFile},live journal 已清空。`);\r\n console.log('verify/rebuild 自动从快照基点重放,无需额外操作。');\r\n return 0;\r\n }\r\n default:\r\n console.error(`unknown profile subcommand: ${sub}`);\r\n return 1;\r\n }\r\n }\r\n\r\n case 'burn': {\r\n const yes = rest.includes('--yes');\r\n const all = rest.includes('--all');\r\n const plan = planBurn(guard, paths, all);\r\n console.log('预演(不会执行):' );\r\n for (const p of plan) console.log(` [${p.exists ? '存在' : '无 '}] ${p.target.file ?? p.target.dir} ${p.target.note}`);\r\n if (!yes) {\r\n console.log('\\n此操作会让心跳 agent 失忆。确认执行请加 --yes(' + (all ? '含 --all 连用户设定' : '用户设定保留') + ')');\r\n return 0;\r\n }\r\n const result = executeBurn(guard, paths, { all });\r\n console.log(`BURNED: ${result.burned.length} 项;MISSING: ${result.missing.length} 项`);\r\n return 0;\r\n }\r\n\r\n case 'migrate': {\r\n if (sub === 'export') {\r\n const defaultOut = path.join(paths.exportsDir, `heartbeat-memory-${new Date().toISOString().slice(0, 10)}.hbmig`);\r\n const outfile = rest[0] ?? defaultOut;\r\n let outCanon: string;\r\n try {\r\n outCanon = guard.assert(outfile);\r\n } catch {\r\n console.error(`导出文件必须落在插件 data/ 目录内(路径守卫拒绝):${outfile}\\n默认位置:${defaultOut}`);\r\n return 1;\r\n }\r\n const [pw1, pw2] = await readLines(['设置口令(用于加密迁移包): ', '再输入一次确认: ']);\r\n if (!pw1 || pw1 !== pw2) {\r\n console.error('两次输入不一致或为空,已取消。');\r\n return 1;\r\n }\r\n const { entries, progress } = collectMigrationEntries(guard, paths);\r\n if (entries.length === 0) {\r\n console.log('没有可打包的记忆文件(data/ 是空的)。');\r\n return 1;\r\n }\r\n fs.mkdirSync(path.dirname(outCanon), { recursive: true });\r\n fs.writeFileSync(outCanon, encryptContainer(entries, pw1), 'utf8');\r\n console.log(`已打包 ${entries.length} 个文件 → ${outCanon}`);\r\n console.log(` 打包:${progress.packed.join(', ')}`);\r\n if (progress.missing.length > 0) console.log(` 跳过(不存在):${progress.missing.join(', ')}`);\r\n console.log('容器是口令加密的,可安全拷贝到新机器;DPAPI 会在导入时用新机器重新加密。');\r\n return 0;\r\n }\r\n if (sub === 'import') {\r\n const infile = rest[0];\r\n if (!infile) {\r\n console.error('usage: migrate import <container-file>');\r\n return 1;\r\n }\r\n const [pw] = await readLines(['输入迁移包口令: ']);\r\n let text: string;\r\n try {\r\n text = fs.readFileSync(infile, 'utf8');\r\n } catch {\r\n console.error(`读不到迁移包:${infile}`);\r\n return 1;\r\n }\r\n let files;\r\n try {\r\n files = decryptContainer(text, pw ?? '');\r\n } catch (e) {\r\n console.error(String(e instanceof Error ? e.message : e));\r\n return 1;\r\n }\r\n const result = applyMigrationEntries(guard, paths, files.files);\r\n console.log(`恢复 ${result.restored.length} 个文件;备份 ${result.backedUp.length} 个被覆盖文件;跳过 ${result.skipped.length} 个。`);\r\n for (const r of result.restored) console.log(` 恢复: ${r}`);\r\n for (const b of result.backedUp) console.log(` 备份: ${b}.bak-migrate-*`);\r\n if (result.skipped.length > 0) console.log(` 跳过: ${result.skipped.join(', ')}`);\r\n console.log('重启 DSH 后生效。');\r\n return 0;\r\n }\r\n console.error(`unknown migrate subcommand: ${sub}`);\r\n return 1;\r\n }\r\n\r\n case 'sessions': {\r\n // Read-only enumeration of the host's persisted sessions (ids from the\r\n // on-disk store; titles live server-side and are not listed here).\r\n const root = path.join(os.homedir(), '.dsh', 'sessions');\r\n let found = 0;\r\n if (fs.existsSync(root)) {\r\n let own: string | null = null;\r\n try {\r\n own = (JSON.parse(loadEncryptedText(guard, path.join(paths.dataDir, 'gate.json')) ?? '{}') as { sessionId?: string }).sessionId ?? null;\r\n } catch { /* gate.json absent or unreadable */ }\r\n for (const slug of fs.readdirSync(root)) {\r\n for (const id of fs.readdirSync(path.join(root, slug))) {\r\n found += 1;\r\n const mark = id === own ? ' ← 心跳正身' : '';\r\n console.log(`${id} [${slug}]${mark}`);\r\n }\r\n }\r\n }\r\n if (found === 0) console.log('(no persisted sessions found)');\r\n return 0;\r\n }\r\n\r\n case 'bind': {\r\n const { loadBindings, addBinding, removeBinding, bindingsFilePath } = await import('../core/bindings.js');\r\n switch (sub) {\r\n case 'list': {\r\n const data = loadBindings(guard, paths.settingsDir);\r\n let own: string | null = null;\r\n try {\r\n own = (JSON.parse(loadEncryptedText(guard, path.join(paths.dataDir, 'gate.json')) ?? '{}') as { sessionId?: string }).sessionId ?? null;\r\n } catch { /* absent */ }\r\n if (own) console.log(`心跳正身: ${own}(决策轮次发生地;bind remove 它 = 重置正身)`);\r\n for (const b of data.bindings) {\r\n console.log(`${b.sessionId} deliver:${b.deliver ? '√' : '×'} observe:${b.observe ? '√' : '×'}`);\r\n }\r\n if (data.bindings.length === 0 && !own) console.log('(no bindings — expressions stay in the dedicated heartbeat session)');\r\n return 0;\r\n }\r\n case 'add': {\r\n const id = rest[0];\r\n if (!id || !id.startsWith('session-')) {\r\n console.error('usage: bind add <sessionId> [--observe] [--no-deliver] (see: sessions list)');\r\n return 1;\r\n }\r\n const observe = rest.includes('--observe') || rest.includes('--observe-only');\r\n const deliver = !rest.includes('--no-deliver') && !rest.includes('--observe-only');\r\n const b = addBinding(guard, paths.settingsDir, id, { deliver, observe });\r\n console.log(`BOUND ${b.sessionId} deliver:${b.deliver} observe:${b.observe}`);\r\n return 0;\r\n }\r\n case 'remove': {\r\n const id = rest[0];\r\n if (!id) {\r\n console.error('usage: bind remove <sessionId>');\r\n return 1;\r\n }\r\n console.log(removeBinding(guard, paths.settingsDir, id) ? `UNBOUND ${id}` : 'NOT_FOUND');\r\n // Unbinding the HOME session resets it: the next beat creates a\r\n // fresh dedicated session (the old one goes quiet after restart).\r\n try {\r\n const state = JSON.parse(loadEncryptedText(guard, path.join(paths.dataDir, 'gate.json')) ?? '{}') as { sessionId?: string };\r\n if (state.sessionId === id) {\r\n fs.rmSync(guard.assert(path.join(paths.dataDir, 'gate.json')), { force: true });\r\n console.log('注意:这是心跳正身会话。已重置——下次心跳将创建新的正身会话(旧会话不再有心跳)');\r\n appendAuditLine(paths.logsDir + '/heartbeat.jsonl', { event: 'home_reset', oldSessionId: id });\r\n }\r\n } catch { /* gate.json absent: nothing to reset */ }\r\n return 0;\r\n }\r\n default:\r\n console.error('usage: bind list | add <sessionId> | remove <sessionId>');\r\n return 1;\r\n }\r\n }\r\n\r\n case 'preset': {\r\n const id = flag(argv, '--id') ?? BUNDLED_PRESET_ID;\r\n // The plugin installs into the roster's own user root; the CLI has no\r\n // roster, so it reports/uses the conventional one ($DSH_HOME or ~/.dsh).\r\n const root = conventionalUserPresetRoot();\r\n const status = presetStatus(import.meta.url, id, root);\r\n if (sub === undefined || sub === 'status') {\r\n console.log(`preset id : ${status.id}`);\r\n console.log(`installed : ${status.installed ? 'yes' : 'no'}`);\r\n console.log(`target dir : ${status.dir}`);\r\n console.log(`bundled at : ${status.bundledDir ?? '(not found next to the plugin)'}`);\r\n if (status.installed) {\r\n console.log(\r\n `composition : ${status.compositionMatches ? 'matches the bundled template' : 'differs from the bundled template (hand-edited, or an older version)'}`,\r\n );\r\n }\r\n if (!status.installed) {\r\n console.log('hint: the plugin installs this itself on the next DSH start (installPreset=true, default);');\r\n console.log(' or run `preset install` now.');\r\n }\r\n return status.installed ? 0 : 1;\r\n }\r\n if (sub === 'install') {\r\n const result = installBundledPreset({\r\n moduleUrl: import.meta.url,\r\n id,\r\n root,\r\n force: rest.includes('--force'),\r\n });\r\n console.log(describeInstall(result));\r\n return result.action === 'error' ? 1 : 0;\r\n }\r\n console.error('usage: preset status | install [--force] [--id <presetId>]');\r\n return 1;\r\n }\r\n\r\n default:\r\n console.error(`unknown command: ${cmd}`);\r\n console.log(usage());\r\n return 1;\r\n }\r\n}\r\n\r\nif (process.argv[1] && import.meta.url === new URL(`file:///${process.argv[1].replace(/\\\\/g, '/')}`).href) {\r\n // Direct execution guard; the CLI is also importable for tests.\r\n void main(process.argv.slice(2)).then((code) => { process.exitCode = code; });\r\n}\r\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 /** 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 { 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 { dir: 'tmp', note: '解锁临时文件(崩溃残留的解密明文是最该烧的东西)' },\n { dir: 'logs', note: '审计与决策日志' },\n { dir: 'exports', note: '导出产物' },\n];\n\nconst SETTINGS_DIR = 'settings'; // excluded unless --all\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!;\n if (!all && rel === SETTINGS_DIR) continue;\n const abs = path.join(paths.dataDir, rel);\n let exists = false;\n try {\n exists = fs.existsSync(guard.assert(abs));\n } catch {\n exists = false;\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 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"]}
|
|
@@ -7,8 +7,8 @@ import {
|
|
|
7
7
|
inboxFileExists,
|
|
8
8
|
inboxFilePath,
|
|
9
9
|
inboxHealthCheck
|
|
10
|
-
} from "./chunk-
|
|
11
|
-
import "./chunk-
|
|
10
|
+
} from "./chunk-63FUJLIF.js";
|
|
11
|
+
import "./chunk-IFTFDHZX.js";
|
|
12
12
|
export {
|
|
13
13
|
dedupeItems,
|
|
14
14
|
inboxAppend,
|
|
@@ -19,4 +19,4 @@ export {
|
|
|
19
19
|
inboxFilePath,
|
|
20
20
|
inboxHealthCheck
|
|
21
21
|
};
|
|
22
|
-
//# sourceMappingURL=inbox-
|
|
22
|
+
//# sourceMappingURL=inbox-57NHQHY3.js.map
|