From 142ed3a82582d627ddb3332265897dfa7affdc3a Mon Sep 17 00:00:00 2001 From: claude code agent 227 Date: Fri, 26 Jun 2026 00:18:56 +0300 Subject: [PATCH] chore(git-sync): drop stray build/ artifacts re-introduced during rebase build/ is gitignored and compiled in CI/Docker; a few files leaked back into the tree while replaying commits onto develop. Remove them so the package keeps a single source of truth (src/). --- packages/git-sync/build/engine/cycle.d.ts | 70 ---------------- packages/git-sync/build/engine/cycle.js | 97 ---------------------- packages/git-sync/build/lib/page-file.d.ts | 50 ----------- packages/git-sync/build/lib/page-file.js | 72 ---------------- 4 files changed, 289 deletions(-) delete mode 100644 packages/git-sync/build/engine/cycle.d.ts delete mode 100644 packages/git-sync/build/engine/cycle.js delete mode 100644 packages/git-sync/build/lib/page-file.d.ts delete mode 100644 packages/git-sync/build/lib/page-file.js diff --git a/packages/git-sync/build/engine/cycle.d.ts b/packages/git-sync/build/engine/cycle.d.ts deleted file mode 100644 index ba194865..00000000 --- a/packages/git-sync/build/engine/cycle.d.ts +++ /dev/null @@ -1,70 +0,0 @@ -import { VaultGit } from "./git.js"; -import { GitSyncClient } from "./client.types.js"; -import { Settings } from "./settings.js"; -/** - * Absolute-path filesystem primitives the cycle needs. Injected (not imported) - * so the engine stays IO-free and unit-testable. `mkdir` is recursive; `rm` is - * force (a missing file is a no-op). - */ -export interface CycleFs { - readFile: (absPath: string) => Promise; - writeFile: (absPath: string, text: string) => Promise; - mkdir: (absDir: string) => Promise; - rm: (absPath: string) => Promise; -} -export interface RunCycleDeps { - spaceId: string; - /** The Docmost seam (reads for pull, writes for push). */ - client: GitSyncClient; - /** The per-space git vault (a real working repo). */ - vault: VaultGit; - /** Engine settings; `vaultPath` roots the relPath -> absolute-path mapping. */ - settings: Settings; - fs: CycleFs; - log: (line: string) => void; - /** - * Delete-cap hook (the ONLY caller-specific policy). Called with the push - * dry-run's planned delete count (`Number.POSITIVE_INFINITY` when the dry-run - * itself failed, so the hook can fail safe) and the live client; returns the - * client to use for the REAL apply. The default (omitted) applies every op - * unmodified. gitmost uses it to neutralize deletes when over its cap. - * - * When omitted, NO dry-run is performed (one fewer push planning pass). - */ - resolveApplyClient?: (plannedDeletes: number, client: GitSyncClient) => GitSyncClient; -} -export interface RunCycleResult { - ran: boolean; - /** Set when the cycle short-circuited without running pull/push. */ - skipped?: "merge-in-progress"; - pull?: { - written: number; - deleted: number; - conflict: boolean; - }; - push?: { - mode: string; - failures: number; - }; -} -/** - * Run ONE full reconcile cycle for a space: PULL (Docmost -> vault) then PUSH - * (vault -> Docmost), under the engine's required branch choreography. This is - * the single entry point the app drives — it owns the staging order so it can - * never drift from the engine it ships with. - * - * Staging (the ⭐ data-loss-critical order, SPEC §6/§9): - * 1. assertGitAvailable + ensureRepo (the git state store must exist). - * 2. refuse on an unresolved merge (a prior conflicting pull); next checkout - * would fail otherwise. - * 3. ensureBranch('docmost','main') + checkout('docmost'). Pull writes MUST - * land on `docmost`, not `main`: applyPullActions commits on `docmost`, - * then checks out `main` and merges docmost -> main. Writing Docmost - * content straight onto `main` would clobber local file edits before push - * can diff them. - * 4. PULL: readExisting -> listSpaceTree -> computePullActions -> apply. - * 5. PUSH: optional dry-run to feed the delete-cap hook, then the real apply. - * - * Lock + cap POLICY live in the caller; this owns only the mechanics. - */ -export declare function runCycle(deps: RunCycleDeps): Promise; diff --git a/packages/git-sync/build/engine/cycle.js b/packages/git-sync/build/engine/cycle.js deleted file mode 100644 index 92e3be3c..00000000 --- a/packages/git-sync/build/engine/cycle.js +++ /dev/null @@ -1,97 +0,0 @@ -import { readExisting, computePullActions, applyPullActions } from "./pull.js"; -import { runPush } from "./push.js"; -/** - * Run ONE full reconcile cycle for a space: PULL (Docmost -> vault) then PUSH - * (vault -> Docmost), under the engine's required branch choreography. This is - * the single entry point the app drives — it owns the staging order so it can - * never drift from the engine it ships with. - * - * Staging (the ⭐ data-loss-critical order, SPEC §6/§9): - * 1. assertGitAvailable + ensureRepo (the git state store must exist). - * 2. refuse on an unresolved merge (a prior conflicting pull); next checkout - * would fail otherwise. - * 3. ensureBranch('docmost','main') + checkout('docmost'). Pull writes MUST - * land on `docmost`, not `main`: applyPullActions commits on `docmost`, - * then checks out `main` and merges docmost -> main. Writing Docmost - * content straight onto `main` would clobber local file edits before push - * can diff them. - * 4. PULL: readExisting -> listSpaceTree -> computePullActions -> apply. - * 5. PUSH: optional dry-run to feed the delete-cap hook, then the real apply. - * - * Lock + cap POLICY live in the caller; this owns only the mechanics. - */ -export async function runCycle(deps) { - const { spaceId, client, vault, settings, fs, log, resolveApplyClient } = deps; - const vaultRoot = settings.vaultPath; - const abs = (relPath) => `${vaultRoot}/${relPath}`; - // 1. The engine state store is git: make sure the repo + branches exist - // before any tracked-file listing or diff. - await vault.assertGitAvailable(); - await vault.ensureRepo(); - // 2. Refuse to run on top of an unresolved merge (SPEC §9): a prior - // conflicting pull leaves the vault mid-merge; the next checkout would fail. - if (await vault.isMergeInProgress()) { - log(`vault has an unresolved merge — resolve it (or 'git merge --abort') ` + - `and re-run (SPEC §9); skipping cycle.`); - return { ran: false, skipped: "merge-in-progress" }; - } - // 3. Pull writes happen on `docmost`; be on it BEFORE applying (see docstring). - await vault.ensureBranch("docmost", "main"); - await vault.checkout("docmost"); - // 4. PULL -------------------------------------------------------------------- - const existing = await readExisting({ - listTracked: () => vault.listTrackedFiles("*.md"), - readFile: (relPath) => fs.readFile(abs(relPath)), - }); - const tree = await client.listSpaceTree(spaceId); - const pullActions = computePullActions({ - pages: tree.pages, - treeComplete: tree.complete, - existing, - }); - const pullResult = await applyPullActions({ - client, - git: vault, - writeFile: (absPath, text) => fs.writeFile(absPath, text), - mkdir: (absDir) => fs.mkdir(absDir), - rm: (absPath) => fs.rm(absPath), - }, pullActions, vaultRoot); - // 5. PUSH -------------------------------------------------------------------- - const pushDeps = { - settings, - git: vault, - makeClient: () => client, - readFile: (relPath) => fs.readFile(abs(relPath)), - writeFile: (relPath, text) => fs.writeFile(abs(relPath), text), - log, - }; - let applyClient = client; - if (resolveApplyClient) { - // Plan the push as a DRY-RUN first to read the delete count, then let the - // caller decide the apply client (e.g. neutralize deletes over a cap). A - // failed dry-run yields Infinity so the hook can fail safe. - let plannedDeletes; - try { - const dry = await runPush(pushDeps, { dryRun: true }); - plannedDeletes = dry.planned?.deletes ?? 0; - } - catch (err) { - log(`push dry-run planning failed (${err instanceof Error ? err.message : String(err)}); deferring deletion policy to the cap hook (fail-safe).`); - plannedDeletes = Number.POSITIVE_INFINITY; - } - applyClient = resolveApplyClient(plannedDeletes, client); - } - const pushResult = await runPush({ ...pushDeps, makeClient: () => applyClient }, { dryRun: false }); - return { - ran: true, - pull: { - written: pullResult.written, - deleted: pullResult.deleted, - conflict: pullResult.merge.conflict, - }, - push: { - mode: pushResult.mode, - failures: pushResult.failures?.length ?? 0, - }, - }; -} diff --git a/packages/git-sync/build/lib/page-file.d.ts b/packages/git-sync/build/lib/page-file.d.ts deleted file mode 100644 index ea961242..00000000 --- a/packages/git-sync/build/lib/page-file.d.ts +++ /dev/null @@ -1,50 +0,0 @@ -/** - * The native-Obsidian page-file format (design: docs/backlog/git-sync-thin-meta.md). - * A page file is CLEAN markdown with a minimal YAML frontmatter carrying ONLY the - * page's durable identity: - * - * --- - * gitmost_id: 019ef6fc-2638-7ce1-9ce3-2756ce038480 - * --- - * - * - * Everything else is derived (title = filename, parentPageId = enclosing folder, - * spaceId = the vault, updatedAt = git). `gitmost_id` (a Docmost pageId) is the - * only non-derivable bit and travels WITH the file so identity survives any move, - * even one git's rename detection misses. Third-party editors (Obsidian, …) see - * clean markdown; the frontmatter is hidden in their preview. - * - * No backward-compat with the old `docmost:meta` format: vaults are a cache, wiped - * and rebuilt native. A file WITHOUT a `gitmost_id` frontmatter is an un-tracked - * (e.g. hand-written) file -> the caller ADOPTS it (creates a page, writes the id). - */ -/** - * The frontmatter key carrying the Docmost pageId. NAMESPACED (not a bare `id`) - * so it never collides with a user's own frontmatter fields. - */ -export declare const ID_KEY = "gitmost_id"; -/** - * Parse a page file into its identity (`id`) and clean markdown `body`. Tolerant: - * a file with no frontmatter (a hand-written third-party file) returns `id: null` - * and the whole text as the body — the caller then ADOPTS it (creates a page, - * writes the id back). - * - * KNOWN LIMITATION (phase 4 — adoption, see docs/backlog/git-sync-thin-meta.md): - * a leading frontmatter block is stripped from `body` even when it carries NO - * `gitmost_id` but DOES carry the user's own Obsidian properties (`tags:` etc.). - * On adoption those fields are not yet round-tripped — `serializePageFile` - * write-back persists only `gitmost_id`. Preserving arbitrary user frontmatter - * across the Docmost round-trip (BOTH adoption write-back AND the next pull's - * re-serialize) is deferred to the adoption phase; until then, do NOT roll the - * native format onto a real Obsidian vault whose notes carry properties. - */ -export declare function parsePageFile(full: string): { - id: string | null; - body: string; -}; -/** - * Serialize a page into the thin format: `id` frontmatter + a blank line + the - * clean body + a trailing newline. Deterministic so an unchanged page re-syncs to - * byte-identical output (no churn — the loop-guard relies on it). - */ -export declare function serializePageFile(id: string, body: string): string; diff --git a/packages/git-sync/build/lib/page-file.js b/packages/git-sync/build/lib/page-file.js deleted file mode 100644 index 3125f08a..00000000 --- a/packages/git-sync/build/lib/page-file.js +++ /dev/null @@ -1,72 +0,0 @@ -/** - * The native-Obsidian page-file format (design: docs/backlog/git-sync-thin-meta.md). - * A page file is CLEAN markdown with a minimal YAML frontmatter carrying ONLY the - * page's durable identity: - * - * --- - * gitmost_id: 019ef6fc-2638-7ce1-9ce3-2756ce038480 - * --- - * - * - * Everything else is derived (title = filename, parentPageId = enclosing folder, - * spaceId = the vault, updatedAt = git). `gitmost_id` (a Docmost pageId) is the - * only non-derivable bit and travels WITH the file so identity survives any move, - * even one git's rename detection misses. Third-party editors (Obsidian, …) see - * clean markdown; the frontmatter is hidden in their preview. - * - * No backward-compat with the old `docmost:meta` format: vaults are a cache, wiped - * and rebuilt native. A file WITHOUT a `gitmost_id` frontmatter is an un-tracked - * (e.g. hand-written) file -> the caller ADOPTS it (creates a page, writes the id). - */ -/** - * The frontmatter key carrying the Docmost pageId. NAMESPACED (not a bare `id`) - * so it never collides with a user's own frontmatter fields. - */ -export const ID_KEY = "gitmost_id"; -/** Leading YAML frontmatter block: `---\n…\n---` at the very start of the file. */ -const FRONTMATTER_RE = /^?---\n([\s\S]*?)\n---\n?/; -/** The top-level `: ` line inside the frontmatter (quotes optional). */ -function readIdFromYaml(yaml) { - const re = new RegExp(`^${ID_KEY}:\\s*(.+?)\\s*$`); - for (const line of yaml.split("\n")) { - const m = line.match(re); - if (m) { - const v = m[1].trim().replace(/^["']|["']$/g, ""); - return v === "" ? null : v; - } - } - return null; -} -/** - * Parse a page file into its identity (`id`) and clean markdown `body`. Tolerant: - * a file with no frontmatter (a hand-written third-party file) returns `id: null` - * and the whole text as the body — the caller then ADOPTS it (creates a page, - * writes the id back). - * - * KNOWN LIMITATION (phase 4 — adoption, see docs/backlog/git-sync-thin-meta.md): - * a leading frontmatter block is stripped from `body` even when it carries NO - * `gitmost_id` but DOES carry the user's own Obsidian properties (`tags:` etc.). - * On adoption those fields are not yet round-tripped — `serializePageFile` - * write-back persists only `gitmost_id`. Preserving arbitrary user frontmatter - * across the Docmost round-trip (BOTH adoption write-back AND the next pull's - * re-serialize) is deferred to the adoption phase; until then, do NOT roll the - * native format onto a real Obsidian vault whose notes carry properties. - */ -export function parsePageFile(full) { - const text = (full ?? "").replace(/\r\n/g, "\n"); - // Native format: a `gitmost_id` YAML frontmatter. Anything else (no frontmatter, - // or frontmatter without the key) is an un-tracked file -> adopt. - const fm = text.match(FRONTMATTER_RE); - if (fm) { - return { id: readIdFromYaml(fm[1]), body: text.slice(fm[0].length).trim() }; - } - return { id: null, body: text.trim() }; -} -/** - * Serialize a page into the thin format: `id` frontmatter + a blank line + the - * clean body + a trailing newline. Deterministic so an unchanged page re-syncs to - * byte-identical output (no churn — the loop-guard relies on it). - */ -export function serializePageFile(id, body) { - return `---\n${ID_KEY}: ${id}\n---\n\n${body.trim()}\n`; -}