diff --git a/gitp-garden/.logseq-proxy/manifest.json b/gitp-garden/.logseq-proxy/manifest.json index 7359fd1..1bff42f 100644 --- a/gitp-garden/.logseq-proxy/manifest.json +++ b/gitp-garden/.logseq-proxy/manifest.json @@ -67,20 +67,48 @@ "logseq-entity": "[[Logseq/Entity/Definition]]" }, "Logseq/Entity/Proxy/Page": { - "entity-tasks": "[[Logseq/Entity/Proxy/Page/mise/Task/sync]]", + "entity-tasks": "[[Logseq/Entity/Proxy/Page/mise/Task/sync]], [[Logseq/Entity/Proxy/Page/mise/Task/docs/serve]]", "logseq-entity": "[[Logseq/Entity/Definition]]" }, + "Logseq/Entity/Proxy/Page/mise/Task/docs/serve": { + "logseq-entity": "[[Logseq/Entity/Mise/Task]]", + "source-link": "https://github.com/codekiln/logseq-encode-garden/blob/main/mise-tasks/logseq/entity/proxy/page/docs/serve", + "task-config-root": ".", + "task-entrypoint": "mise-tasks/logseq/entity/proxy/page/docs/serve", + "task-files": "{\"mise-tasks/logseq/entity/proxy/page/docs/serve\":\"mise-tasks/logseq/entity/proxy/page/docs/serve\",\"mise-tasks/logseq/entity/proxy/page/docs/index.html\":\"mise-tasks/logseq/entity/proxy/page/docs/index.html\"}", + "task-name": "logseq:entity:proxy:page:docs:serve", + "task-owner": "[[Person/codekiln/GitHub/logseq-encode-garden]]" + }, "Logseq/Entity/Proxy/Page/mise/Task/sync": { "logseq-entity": "[[Logseq/Entity/Mise/Task]]", "source-link": "https://github.com/codekiln/logseq-encode-garden/blob/main/mise-tasks/logseq/entity/proxy/page/sync", "task-config-root": ".", + "task-dependencies": "[[Logseq/Entity/Proxy/Page/mise/Task/docs/serve]]", "task-entrypoint": "mise-tasks/logseq/entity/proxy/page/sync", - "task-files": "{\"mise-tasks/logseq/entity/proxy/page/sync\":\"mise-tasks/logseq/entity/proxy/page/sync\",\"mise-tasks/logseq/entity/proxy/page/lib/core.py\":\"mise-tasks/logseq/entity/proxy/page/lib/core.py\",\"mise-tasks/logseq/entity/proxy/page/lib/companions.py\":\"mise-tasks/logseq/entity/proxy/page/lib/companions.py\"}", + "task-files": "{\"mise-tasks/logseq/entity/proxy/page/sync\":\"mise-tasks/logseq/entity/proxy/page/sync\",\"mise-tasks/logseq/entity/proxy/page/lib/core.py\":\"mise-tasks/logseq/entity/proxy/page/lib/core.py\",\"mise-tasks/logseq/entity/proxy/page/lib/task_imports.py\":\"mise-tasks/logseq/entity/proxy/page/lib/task_imports.py\"}", "task-name": "logseq:entity:proxy:page:sync", "task-owner": "[[Person/codekiln/GitHub/logseq-encode-garden]]" } }, "files": { + "mise-tasks/logseq/entity/proxy/page/docs/index.html": { + "mode": 420, + "sha256": "832ce80b4e705a9a25933ce10fabd69b3e7d8f3eface1eb2f26d27c46bc15d08", + "source": [ + "github.com/codekiln/logseq-encode-garden", + ".", + "mise-tasks/logseq/entity/proxy/page/docs/index.html" + ] + }, + "mise-tasks/logseq/entity/proxy/page/docs/serve": { + "mode": 493, + "sha256": "e13bef969fc38baced4f9a4129a684595b979481eff73037e07526764ed11d85", + "source": [ + "github.com/codekiln/logseq-encode-garden", + ".", + "mise-tasks/logseq/entity/proxy/page/docs/serve" + ] + }, "mise-tasks/logseq/entity/proxy/page/lib/companions.py": { "mode": 420, "sha256": "9527f6bca636edf9c9425c5c774c4333ed028025cdc56de849e0828dc703fc87", @@ -99,9 +127,18 @@ "mise-tasks/logseq/entity/proxy/page/lib/core.py" ] }, + "mise-tasks/logseq/entity/proxy/page/lib/task_imports.py": { + "mode": 420, + "sha256": "11b952bac59727a617009e0692f2b4c41ea1739c7aa486296830b864b7b3415a", + "source": [ + "github.com/codekiln/logseq-encode-garden", + ".", + "mise-tasks/logseq/entity/proxy/page/lib/task_imports.py" + ] + }, "mise-tasks/logseq/entity/proxy/page/sync": { "mode": 493, - "sha256": "4dc4adbcd690cb3d37fac58a7471454dc019d57160e8afc609d2508b1632a5ff", + "sha256": "d67da47d08b33cb0fba54f60555cfe9c7a87ba17257fd97b937e123629c32b0f", "source": [ "github.com/codekiln/logseq-encode-garden", ".", @@ -205,6 +242,16 @@ "page": "Logseq/Entity/Asset/B2", "source_graph": "." }, + "github.com/codekiln/logseq-encode-garden::.::Logseq/Entity/Definition": { + "files": [], + "page": "Logseq/Entity/Definition", + "source_graph": "." + }, + "github.com/codekiln/logseq-encode-garden::.::Logseq/Entity/Mise/Task": { + "files": [], + "page": "Logseq/Entity/Mise/Task", + "source_graph": "." + }, "github.com/codekiln/logseq-encode-garden::.::Logseq/Entity/Podcast/Episode": { "files": [], "page": "Logseq/Entity/Podcast/Episode", @@ -212,12 +259,26 @@ }, "github.com/codekiln/logseq-encode-garden::.::Logseq/Entity/Proxy/Page": { "files": [ + "mise-tasks/logseq/entity/proxy/page/docs/index.html", + "mise-tasks/logseq/entity/proxy/page/docs/serve", "mise-tasks/logseq/entity/proxy/page/lib/companions.py", "mise-tasks/logseq/entity/proxy/page/lib/core.py", + "mise-tasks/logseq/entity/proxy/page/lib/task_imports.py", "mise-tasks/logseq/entity/proxy/page/sync" ], "page": "Logseq/Entity/Proxy/Page", "source_graph": "." + }, + "github.com/codekiln/logseq-encode-garden::.::Logseq/Entity/Proxy/Page/mise/Task/sync": { + "files": [ + "mise-tasks/logseq/entity/proxy/page/docs/index.html", + "mise-tasks/logseq/entity/proxy/page/docs/serve", + "mise-tasks/logseq/entity/proxy/page/lib/companions.py", + "mise-tasks/logseq/entity/proxy/page/lib/core.py", + "mise-tasks/logseq/entity/proxy/page/sync" + ], + "page": "Logseq/Entity/Proxy/Page/mise/Task/sync", + "source_graph": "." } }, "pages": { @@ -336,6 +397,11 @@ ".", "Logseq/Entity/Proxy/Page" ], + "Logseq/Entity/Proxy/Page/mise/Task/docs/serve": [ + "github.com/codekiln/logseq-encode-garden", + ".", + "Logseq/Entity/Proxy/Page/mise/Task/docs/serve" + ], "Logseq/Entity/Proxy/Page/mise/Task/sync": [ "github.com/codekiln/logseq-encode-garden", ".", @@ -343,6 +409,19 @@ ] }, "tasks": { + "Logseq/Entity/Proxy/Page/mise/Task/docs/serve": { + "identity": [ + "github.com/codekiln/logseq-encode-garden", + ".", + "[[Person/codekiln/GitHub/logseq-encode-garden]]", + ".", + "logseq:entity:proxy:page:docs:serve" + ], + "mapping": { + "mise-tasks/logseq/entity/proxy/page/docs/index.html": "mise-tasks/logseq/entity/proxy/page/docs/index.html", + "mise-tasks/logseq/entity/proxy/page/docs/serve": "mise-tasks/logseq/entity/proxy/page/docs/serve" + } + }, "Logseq/Entity/Proxy/Page/mise/Task/sync": { "identity": [ "github.com/codekiln/logseq-encode-garden", @@ -352,8 +431,8 @@ "logseq:entity:proxy:page:sync" ], "mapping": { - "mise-tasks/logseq/entity/proxy/page/lib/companions.py": "mise-tasks/logseq/entity/proxy/page/lib/companions.py", "mise-tasks/logseq/entity/proxy/page/lib/core.py": "mise-tasks/logseq/entity/proxy/page/lib/core.py", + "mise-tasks/logseq/entity/proxy/page/lib/task_imports.py": "mise-tasks/logseq/entity/proxy/page/lib/task_imports.py", "mise-tasks/logseq/entity/proxy/page/sync": "mise-tasks/logseq/entity/proxy/page/sync" } } diff --git a/gitp-garden/logseq/config.edn b/gitp-garden/logseq/config.edn index 8d15cd2..a8bc7c3 100644 --- a/gitp-garden/logseq/config.edn +++ b/gitp-garden/logseq/config.edn @@ -320,7 +320,7 @@ :logseq-proxy-url :logseq-proxy-codeforge-url :logseq-proxy-last-sync-date :entity-proxy-destination-properties :entity-tasks :task-owner :task-config-root :task-name - :task-entrypoint :task-files} + :task-entrypoint :task-files :task-dependencies} ;; Create a page for all properties. ;; Default value: true diff --git a/gitp-garden/mise-tasks/logseq/entity/proxy/page/docs/index.html b/gitp-garden/mise-tasks/logseq/entity/proxy/page/docs/index.html new file mode 100644 index 0000000..88fd98f --- /dev/null +++ b/gitp-garden/mise-tasks/logseq/entity/proxy/page/docs/index.html @@ -0,0 +1,174 @@ + + + + + + +How Logseq proxies work + + + +
Logseq / Proxy Page
+
+ +
+
+
A page you own elsewhere, readable here
+

How Logseq proxies work

+

A proxy keeps a source page’s name and content in another garden. The page discloses its source. Sync brings along the definitions and tools needed to use it.

+

The useful promise: edit the source, preview the import, then refresh the destination. Each destination can keep its own publication settings while sharing the source’s content.

+

The guide describes the merged implementation at the commit above. PR #199 — preserve proxy identity across worktrees is merged and included here, explained under parallel agents.

+
+
+

The page-to-page relationship stays visible

+

A source named GitP/A/Session/24/12/04-Wed becomes a destination page with the same name. Each garden has its own Markdown file. The destination’s frontmatter says where the source lives and when it was copied.

+
+
Source garden

Page body + frontmatter
Entity definitions
Declared tools + local assets

Sync

Resolve source
Build import plan
Check ownership + changes

Destination garden

Same page name
Proxy source properties
Copied definitions + tools

+
.logseq-proxy/manifest.json accompanies the imported files: source identities, script ownership, last imported script hashes, and declarations for onward imports.
+
logseq-proxy-url:: logseq://graph/logseq-encode-garden?page=GitP%2FA%2FSession%2F24%2F12%2F04-Wed
+logseq-proxy-codeforge-url:: https://github.com/codekiln/logseq-encode-garden/blob/main/pages/GitP___A___Session___24___12___04-Wed.md
+logseq-proxy-last-sync-date:: [[2026-10-07]]
+

Example after a refresh from main. The Logseq URL opens the source graph; the forge URL identifies its repository and source file; the date records the sync day. The membership [[Logseq/Entity/Proxy/Page]] is added beside the page’s existing entity types.

+

Copying allows Logseq to query and display the content locally. The destination can be committed, cloned, published, and read while the source garden is closed. Sync runs when invoked; it does not continuously watch either garden.

+

Code: page creation, frontmatter, assets, and embeds.

+
+
+

From a source edit to a reviewed import

+

Preview and apply use the same planning algorithm. The preview prints the planned files and property changes. Applying runs a fresh plan and then checks that the files have not changed while that plan was being built.

+
+
+

Add a page that lives in another garden

Choose a local source graph, a destination graph, and the exact logical page name.

+
Locate

Supply --source for the first import. Both graph roots must contain pages/ and logseq/. The task reads local files; it does not clone or fetch the source.

+
Discover

Read the page’s logseq-entity links, visit their definitions, follow entity-tasks and task-dependencies, and copy the declared task reference pages and mapped implementation files. A visited set prevents repeated traversal of shared or cyclic definitions and task dependencies. Add --follow-embeds to include embedded pages recursively; ordinary wikilinks are not followed.

+
Preview

Plan the new proxy page, proxy membership, source URLs, sync date, supporting files, and manifest. Copy linked ../assets/… files when present. Missing local assets or embedded pages produce warnings; missing required tasks or implementations stop the import.

+
Validate

A destination page with the same name and no proxy URL is a collision. An existing script without an ownership record is a collision too—even if its contents match. Competing source claims stop application.

+
Apply

Rerun with --apply. The task locks the destination graph, checks the plan’s file preconditions, stages replacements, and saves rollback information before replacing files.

+
Review & commit

Review the destination diff. Commit the proxy pages, imported task files, copied assets allowed by the garden’s asset policy, and manifest together. Sync writes files; it does not stage, commit, push, or merge.

+
+ +
# Preview a first import from the registered source checkout
+mise run logseq:entity:proxy:page:sync \
+  --source /path/to/logseq-encode-garden \
+  --destination /path/to/gitpa/gitp-garden \
+  --page 'GitP/A/Session/24/12/04-Wed'
+
+# Repeat that command with --apply after reviewing the preview.
+# For later previews, --source can be omitted when discovery succeeds.
+mise run logseq:entity:proxy:page:sync \
+  --destination /path/to/gitpa/gitp-garden \
+  --page 'GitP/A/Session/24/12/04-Wed'
+

Edit shared content at its source. Proxy page bodies and copied assets are replaced on refresh. Keep local publication values in destination-owned properties. The script edit protection does not extend to every copied file.

+

Code: destination-owned properties, source discovery, companion traversal and ownership, application and rollback.

+
+
+

Different sources can share one destination

+

There is no single-source setting for a destination. Each import supplies or resolves its own source, and each page has its own proxy URL. The manifest distinguishes sources by repository + graph path within that repository.

+

Garden A / Music

Repository: github.com/example/music
Graph folder: .
Page: Music/Session/A

Garden B / Reading

Repository: github.com/example/reading
Graph folder: garden
Page: Book/Notes/B

+

One destination garden

pages/Music___Session___A.md ← Garden Apages/Book___Notes___B.md ← Garden B

Illustrative names. Each page keeps its own source metadata. A manifest page record includes the source repository, graph folder, and logical page name.

+
Accepted

Different names and compatible claims

Independent pages and script paths can coexist. Re-importing a shared definition or script from the same repository and graph is recognized as the same source ownership.

Stopped for review

The same destination claimed by another source

The graph has one file per logical page name. Another garden cannot silently replace that page. Two source scripts cannot claim the same destination path, even if their contents happen to match.

+

Entity definitions share this page namespace too. If Music and Reading both supply a definition named Logseq/Entity/Book, importing from the second source stops even when the definition text matches. A definition proxied through an intermediate garden is claimed under that immediate source garden’s identity; the importer does not unify claims by their ultimate upstream origin. Multiple gardens work when all imported page and script claims are compatible, not merely when the requested note names differ.

+

The source tuple lets nested graph folders coexist too. For Git repositories with an origin, identities use repository addresses and relative paths. Without an origin, the code falls back to an absolute local path; that case does not have the same portability guarantee.

+

Code: repository identity and file and page claims. Page frontmatter adds checks for the Logseq source name and forge repository.

+
+
+

Why a manifest exists

+

The page already says what it proxies. The extra information needed for safe script updates is what was imported last time. Today’s source and destination files alone cannot distinguish an upstream change from an edit made locally after import.

+

The same ownership records could be expressed as attributes on task reference pages. A separate JSON file groups the file mappings, modes, and historical hashes without adding operational properties to every visible page. That is a storage choice; the safety comes from retaining and checking the import baseline.

+
Last import

Remember the baseline

The source script was version A. Sync copied A into the destination and recorded A’s hash and file mode in the manifest.

Next import

Compare before replacing

If the destination still matches A, sync can replace it with upstream version B. If the destination is locally edited version C, sync stops for review.

+
+ + + + + +
Manifest sectionInformation retainedRole in the algorithm
filesSource tuple, last imported hash, file modeProtects imported implementation files from local edits and competing source ownership.
pagesRepository, graph folder, logical nameRejects a later claim by a different source garden.
tasksTask identity and source-to-destination mappingFinds imported task files when this proxy garden becomes a source for another garden.
declarationsEntity/task properties and source linkSupplies saved declarations for onward imports from proxy pages.
importsSource graph, requested page, accumulated script pathsReports removed upstream script mappings as cleanup candidates.
+

The manifest has more authority than an index. When a source page is itself a proxy, saved declarations override its entity/task properties during companion discovery. Editing those properties on the proxy page can therefore disagree with what an onward import uses. The declarations are refreshed by sync, but the implementation does not independently reconcile arbitrary manual edits between syncs.

+

This declaration cache was introduced while re-sync preserved destination frontmatter broadly. Re-sync now refreshes source-owned properties, but the cache still exists. Keeping frontmatter authoritative and limiting stored state to ownership, path mappings, and historical hashes is a possible simplification; it is not the current algorithm.

+

The manifest is written with the same staged update and recovery journal as the imported files. Hand-editing hashes to acknowledge a local change would remove the evidence used by the edit check. Deleting the manifest also loses ownership: existing imported scripts then appear unowned and a repeat import stops.

+

Code: manifest validation and saved declaration precedence, onward task path resolution. History: PR #186 — companion task contract and explanation of chained imports.

+
+
+

Commit the import as one change

+

The destination should carry the files someone needs to read its pages and safely refresh its imported tools after cloning. A local server process and recovery scratch files serve a different purpose.

+
+ + + + + + + +
File or stateGit treatmentCurrent behavior
pages/*.mdCommit imported pages and definition/task reference pages.Written by sync; proxy properties live in these files.
mise-tasks/…Commit the imported entrypoint, helpers, and mapped documentation; preserve executable modes.Written only from explicit task-files mappings. Root Mise configuration is not copied automatically.
assets/…Follow the destination’s asset policy; include copied assets that belong in Git.Local ../assets/ links trigger copying. HTTPS media remains a URL and is not downloaded.
.logseq-proxy/manifest.jsonCommit alongside imported files.This garden and Gitpa do not ignore it. It holds ownership history needed by the next import.
.logseq-proxy-transaction/Keep local; never commit a rollback journal.Created only while applying; deleted after success or rollback. An interrupted run can leave it behind. Neither garden currently has an explicit ignore rule for this directory.
Python caches, editor backups, worktreesIgnore as local generated state.The garden ignores __pycache__/, *.pyc, Logseq backup/recycle directories, and dot-prefixed worktree locations.
Docs preview serverCommit its HTML and launcher; keep the running process local.The docs task creates no build output, log file, or saved browser state.
+

Sync does not change .gitignore. After applying, use git status and git diff, then stage the import’s specific files. If an interrupted transaction appears, recover it before staging:

+
mise run logseq:entity:proxy:page:sync \
+  --destination /path/to/destination-garden --recover
+
+# Review again after recovery; then run a fresh preview.
+

Code: recovery and temporary transaction directory. Ignore rules: garden .gitignore and Gitpa PR #12 .gitignore.

+
+
+

Parallel work needs an integration plan

+

Sync protects a destination during application. Git combines changes made in different worktrees later. Those are separate operations, with separate kinds of conflict.

+
Same checkout

Lock, then check what changed

Cooperating sync processes serialize application using a lock on the destination graph directory. After obtaining the lock, a plan must still match the source contents and the destination contents and modes it read. A stale plan stops; rerun it.

Logseq, editors, and other programs do not necessarily honor this lock. It does not freeze either garden against arbitrary external writes.

Separate worktrees

Isolation, then Git integration

Each agent has its own destination files and manifest. Independent page edits can merge cleanly, but imports may also touch shared definitions, shared scripts, and the same JSON manifest. The runtime lock does not coordinate separate worktrees.

+

The current design does not guarantee conflict-free merges. Sorting manifest keys makes output consistent, but adjacent insertions can still conflict in Git. A clean textual merge also needs semantic review: a manifest and its scripts must describe the same imported versions.

+
Assign

Give agents distinct source pages or namespaces. Make shared entity-definition changes in a coordinated change so each consumer imports the same definitions.

Integrate

Bring source changes together, then refresh the destination against that combined source. Prefer one agent to perform the final destination sync, especially when the imported tools or definitions overlap.

Recompute

If branches already contain independent imports, resolve source/page decisions and build a consistent destination from the common pre-import destination state. Reapply the required imports sequentially. Review the resulting files and manifest together rather than guessing conflicting hashes.

Review

Run a fresh preview and check both the page diff and imported script ownership. A same-day repeat with identical inputs should be unchanged. Commit and merge the reviewed set.

+
Why recompute from a consistent baseline?

The sync checks that existing imported scripts match their manifest hashes before it updates them. Combining a manifest from one branch with a script from another can fail that check. Reapplying imports from a common, consistent baseline lets the task produce matching ownership records. This is an integration workflow, not a built-in Git conflict resolver.

+
Source worktrees retain the registered graph identity

Sync can read files from a selected source worktree while deriving the graph name from the primary checkout at the same repository-relative graph path. An issue-named worktree therefore keeps the registered graph's Logseq identity.

PR #199 — preserve proxy identity across worktrees is merged. Forge links identify the chosen worktree branch, or its commit when detached; normal imports from the primary checkout use the remote default branch. After upstream changes merge, refresh from the registered source checkout to update source links. Ownership identities use the repository and graph path, so changing a branch does not create a new ownership claim.

+

A simplified illustration of the documented checks. This control does not read or modify a graph.

+

Code: locking and file preconditions and ownership records and sorted JSON.

+
+
+

See what a proxy discloses

+

Logseq can query the stored properties even when the display configuration hides them. In Gitpa PR #12, :block-hidden-properties also removes the proxy keys from the clickable property editor. The Markdown file contains the full frontmatter.

+
# Find proxy files, regardless of Logseq’s display settings
+rg -n '^logseq-proxy-url::' pages/ --glob '*.md'
+
+# Inspect the file from the December episode example
+sed -n '1,12p' pages/GitP___A___Session___24___12___04-Wed.md
+

That page’s properties are visible in Gitpa PR #12’s checked-in episode file. A presentation-only hiding approach could leave the properties accessible while editing; the current Gitpa configuration does not provide that behavior.

+
+
+

Open the guide or follow the code

+
mise run logseq:entity:proxy:page:docs:serve
+
+# Choose another local port or keep browser selection manual
+mise run logseq:entity:proxy:page:docs:serve --port 8768 --no-open
+

The docs task serves this directory on 127.0.0.1 and opens the default browser unless --no-open is supplied. Stop it with Ctrl-C. This HTML also works when opened directly from disk.

+ +
+ +
+ + + diff --git a/gitp-garden/mise-tasks/logseq/entity/proxy/page/docs/serve b/gitp-garden/mise-tasks/logseq/entity/proxy/page/docs/serve new file mode 100755 index 0000000..f62b86c --- /dev/null +++ b/gitp-garden/mise-tasks/logseq/entity/proxy/page/docs/serve @@ -0,0 +1,47 @@ +#!/usr/bin/env python3 +#MISE description="Open the illustrated Logseq proxy algorithm guide" +#MISE tools={python="3.13.16"} +#USAGE flag "--port " default="8768" help="Local HTTP port" +#USAGE flag "--no-open" help="Serve without launching the default browser" +"""Serve the adjacent proxy guide on localhost; stop with Ctrl-C.""" +import argparse +from functools import partial +from http.server import SimpleHTTPRequestHandler, ThreadingHTTPServer +import os +from pathlib import Path +import sys +import webbrowser + + +def main(): + parser = argparse.ArgumentParser(description=__doc__) + parser.add_argument('--port', type=int, default=8768) + parser.add_argument('--no-open', action='store_true') + args = sys.argv[1:] + if not args and 'usage_port' in os.environ: + args = ['--port', os.environ['usage_port']] + if os.environ.get('usage_no_open') == 'true': + args.append('--no-open') + options = parser.parse_args(args) + if not 0 <= options.port <= 65535: + parser.error('--port must be between 0 and 65535 (0 selects an available port)') + directory = Path(__file__).resolve().parent + handler = partial(SimpleHTTPRequestHandler, directory=str(directory)) + try: + with ThreadingHTTPServer(('127.0.0.1', options.port), handler) as server: + url = f'http://127.0.0.1:{server.server_port}/' + print(f'Logseq proxy guide: {url}\nStop with Ctrl-C.', flush=True) + if not options.no_open: + webbrowser.open(url) + try: + server.serve_forever() + except KeyboardInterrupt: + pass + except OSError as error: + print(f'Cannot serve guide: {error}', file=sys.stderr) + return 1 + return 0 + + +if __name__ == '__main__': + raise SystemExit(main()) diff --git a/gitp-garden/mise-tasks/logseq/entity/proxy/page/lib/task_imports.py b/gitp-garden/mise-tasks/logseq/entity/proxy/page/lib/task_imports.py new file mode 100644 index 0000000..f5adc9e --- /dev/null +++ b/gitp-garden/mise-tasks/logseq/entity/proxy/page/lib/task_imports.py @@ -0,0 +1,286 @@ +"""Plan imports of entity definitions, task references, and executable task files. + +Follow logseq-entity, entity-tasks, and task-dependencies links from the pages +already selected for sync. Read each task reference's task-files mapping to +locate the entrypoint and helpers, and add their copies to the page-sync plan. +Before replacing imported task files, check the destination manifest's source +ownership, last-imported content hashes, and file modes. Update the manifest +in the same plan so later syncs can distinguish upstream changes from local +edits. core.apply_plan writes the completed plan as one recoverable update. +""" +from __future__ import annotations + +import hashlib +import json +from pathlib import Path, PurePosixPath +import re +import stat +import subprocess +from urllib.parse import urlsplit +import tomllib + +import core + +MANIFEST = '.logseq-proxy/manifest.json' + + +def refs(value): + return re.findall(r'\[\[([^\]]+)\]\]', value or '') + + +def repository(graph): + for parent in (graph, *graph.parents): + if (parent / '.git').exists(): + return parent + return graph + + +def repository_identity(repo): + result = subprocess.run(['git', '-C', str(repo), 'remote', 'get-url', 'origin'], capture_output=True, text=True) + if result.returncode == 0: + remote = result.stdout.strip() + if '://' in remote: + parsed = urlsplit(remote) + address = (parsed.hostname or '') + '/' + parsed.path.lstrip('/') + elif ':' in remote and not remote.startswith('/'): + host, path = remote.split(':', 1) + address = host.split('@')[-1] + '/' + path + else: + address = remote + return address.removesuffix('.git').rstrip('/') + return str(repo.resolve()) + + +def relative(value, label): + path = PurePosixPath(value) + if not value or path == PurePosixPath('.') or path.is_absolute() or '..' in path.parts or '\\' in value or path.as_posix() != value: + raise ValueError(f'{label}: expected a normalized repository-relative path: {value}') + return path + + +def safe_file(root, value, label): + path = relative(value, label) + current = root + for part in path.parts: + current = current / part + if current.is_symlink(): + raise ValueError(f'{label}: symlink is unsupported: {value}') + return current + + +def digest(data): + return hashlib.sha256(data).hexdigest() + + +def compatible_config(root): + """Check that the destination Mise config can discover imported file tasks. + + Read mise.toml or .mise.toml at the graph root. When task_config.includes + is set, require mise-tasks (with an optional ./ prefix or trailing slash). + An absent includes setting uses Mise's default file-task discovery. + Reject an explicit list that excludes mise-tasks before planning writes; + malformed TOML also stops the import. + """ + for filename in ('mise.toml', '.mise.toml'): + config = root / filename + if config.exists(): + parsed = tomllib.loads(config.read_text()) + includes = parsed.get('task_config', {}).get('includes') + if includes is not None and not any(str(value).rstrip('/') in ('mise-tasks', './mise-tasks') for value in includes): + raise ValueError(f'{config}: task_config.includes must include mise-tasks to discover imported tasks') + return + + +def load_manifest(data, label): + try: + manifest = json.loads(data) + if not isinstance(manifest, dict) or manifest.get('version') != 1 or not isinstance(manifest.get('files'), dict): + raise ValueError('unsupported schema') + for section in ('files', 'imports', 'pages', 'tasks', 'declarations'): + if not isinstance(manifest.get(section, {}), dict): + raise ValueError(f'{section} must be an object') + for record in manifest.get('files', {}).values(): + if not isinstance(record, dict) or not isinstance(record.get('source'), list) or len(record['source']) != 3 or not all(isinstance(item, str) for item in record['source']) or not isinstance(record.get('mode'), int) or not isinstance(record.get('sha256'), str): + raise ValueError('invalid file ownership record') + for record in manifest.get('tasks', {}).values(): + if not isinstance(record, dict) or not isinstance(record.get('mapping'), dict) or not all(isinstance(key, str) and isinstance(value, str) for key, value in record['mapping'].items()): + raise ValueError('invalid task mapping') + for record in manifest.get('declarations', {}).values(): + if not isinstance(record, dict) or not all(isinstance(key, str) and isinstance(value, str) for key, value in record.items()): + raise ValueError('invalid companion declaration') + for record in manifest.get('imports', {}).values(): + if not isinstance(record, dict) or not isinstance(record.get('files'), list) or not all(isinstance(item, str) for item in record['files']): + raise ValueError('invalid import record') + return manifest + except (ValueError, AttributeError) as exc: + raise ValueError(f'{label}: invalid import manifest: {exc}') from exc + + +def source_manifest(plan): + path = safe_file(plan.source_root, MANIFEST, 'source manifest') + if not path.exists(): + return {} + data = path.read_bytes() + plan.source_expected[path] = data + return load_manifest(data, path) + + +def declarations(props): + return {key: value for key, value in props.items() + if key in ('logseq-entity', 'entity-tasks', 'source-link') or key.startswith('task-')} + + +def source_properties(plan, page, file): + props, _ = core.parse_properties(file.read_text()) + if props.get('logseq-proxy-url'): + latest = source_manifest(plan).get('declarations', {}).get(page) + if latest is not None: + for key in list(props): + if key in ('logseq-entity', 'entity-tasks', 'source-link') or key.startswith('task-'): + del props[key] + props.update(latest) + return props + + +def task_spec(plan, page, props): + required = ('task-owner', 'task-config-root', 'task-name', 'source-link', 'task-entrypoint', 'task-files') + for key in required: + if not props.get(key): + raise ValueError(f'{page}: missing {key}') + repo = repository(plan.source_root) + scope = props['task-config-root'] + if scope != '.': + relative(scope, f'{page} task-config-root') + entry = relative(props['task-entrypoint'], f'{page} task-entrypoint') + name = props['task-name'] + name_path = PurePosixPath(*name.split(':')) + if not name or '/' in name or '\\' in name or any(not part or part in ('.', '..') for part in name.split(':')): + raise ValueError(f'{page}: invalid task-name {name}') + try: + mapping = json.loads(props['task-files']) + except json.JSONDecodeError as exc: + raise ValueError(f'{page}: task-files must be a JSON object') from exc + if not isinstance(mapping, dict) or not mapping or not all(isinstance(k, str) and isinstance(v, str) for k, v in mapping.items()): + raise ValueError(f'{page}: task-files must map source paths to destination paths') + if mapping.get(str(entry)) != str(PurePosixPath('mise-tasks') / name_path): + raise ValueError(f'{page}: task-files must map the entrypoint to mise-tasks/{name_path}') + imported = source_manifest(plan).get('tasks', {}).get(page, {}) + identity = [repository_identity(repo), plan.source_root.relative_to(repo).as_posix(), props['task-owner'], scope, name] + files = [] + for source, destination in mapping.items(): + dest = relative(destination, f'{page} destination') + if dest.parts[0] != 'mise-tasks' or len(dest.parts) < 2: + raise ValueError(f'{page}: task destinations must be implementation files under mise-tasks: {destination}') + if any(part in ('.git', '.logseq-proxy') for part in dest.parts): + raise ValueError(f'{page}: reserved destination {destination}') + actual_source = imported.get('mapping', {}).get(source, source) + if imported and relative(actual_source, f'{page} imported source').parts[0] != 'mise-tasks': + raise ValueError(f'{page}: imported source must be under mise-tasks') + actual_root = plan.source_root if imported else repo + if any(part in ('.git', '.logseq-proxy') for part in relative(actual_source, f'{page} source').parts): + raise ValueError(f'{page}: reserved implementation source {actual_source}') + file = safe_file(actual_root, actual_source, f'{page} source') + safe_file(plan.destination_root, destination, f'{page} destination') + if not file.is_file(): + raise ValueError(f'{page}: missing implementation file {source}') + mode = stat.S_IMODE(file.stat().st_mode) + if source == str(entry) and not mode & 0o111: + raise ValueError(f'{page}: entrypoint is not executable: {source}') + data = file.read_bytes() + plan.source_expected[file] = data + plan.source_modes[file] = mode + source_relative = file.relative_to(repo).as_posix() + files.append((source_relative, destination, data, mode)) + return identity, files + + +def extend_plan(plan): + """Extend the page plan without writing to either garden.""" + compatible_config(plan.destination_root) + manifest_path = safe_file(plan.destination_root, MANIFEST, 'manifest') + if manifest_path.exists(): + manifest = load_manifest(manifest_path.read_bytes(), manifest_path) + else: + manifest = {'version': 1, 'files': {}, 'imports': {}} + records = manifest['files'] + queue = list(plan.pages) + visited = set() + claims = {} + required_tasks = set() + contents = {} + while queue: + page = queue.pop() + if page in visited: + continue + visited.add(page) + file = core.resolve_page(plan.source_root, page) + if file is None or not file.is_file(): + plan.warnings.append(f'Entity definition {page} has no source file; no companion declaration can be read') + continue + props = source_properties(plan, page, file) + manifest.setdefault('declarations', {})[page] = declarations(props) + for entity in refs(props.get('logseq-entity')): + entity_file = core.resolve_page(plan.source_root, entity) + if entity_file is None or not entity_file.is_file(): + plan.warnings.append(f'Entity definition {entity} has no source file; no companion declaration can be read') + continue + core.add_page(plan, entity) + queue.append(entity) + task_refs = refs(props.get('entity-tasks')) + refs(props.get('task-dependencies')) + for task in task_refs: + task_file = core.resolve_page(plan.source_root, task) + if task_file is None or not task_file.is_file(): + raise ValueError(f'{page}: missing required task reference {task}') + task_props = source_properties(plan, task, task_file) + task_spec(plan, task, task_props) + required_tasks.add(task) + core.add_page(plan, task) + queue.append(task) + if page not in required_tasks and not props.get('task-files'): + if props.get('task-entrypoint'): + raise ValueError(f'{page}: missing task-files') + continue + identity, files = task_spec(plan, page, props) + manifest.setdefault('tasks', {})[page] = {'identity': identity, 'mapping': json.loads(props['task-files'])} + for source, destination, data, mode in files: + source_identity = [identity[0], identity[1], source] + claim = {'source': source_identity, 'sha256': digest(data), 'mode': mode} + if destination in claims and claims[destination]['source'] != source_identity: + raise ValueError(f'Competing source files claim {destination}') + claims[destination] = claim + contents[destination] = data + repo = repository(plan.source_root) + page_records = manifest.setdefault('pages', {}) + for page in plan.pages: + identity = [repository_identity(repo), plan.source_root.relative_to(repo).as_posix(), page] + previous = page_records.get(page) + if previous and previous != identity: + raise ValueError(f'{page}: page already imported from a different source graph') + page_records[page] = identity + for destination, claim in claims.items(): + path = safe_file(plan.destination_root, destination, 'task destination') + previous = records.get(destination) + if previous and previous.get('source') != claim['source']: + raise ValueError(f'{destination}: already claimed by a different source') + if path.exists(): + if not path.is_file(): + raise ValueError(f'{destination}: destination is not a regular file') + if not previous: + raise ValueError(f'{destination}: existing implementation is unowned; move it aside before importing') + if digest(path.read_bytes()) != previous.get('sha256') or stat.S_IMODE(path.stat().st_mode) != previous.get('mode'): + raise ValueError(f'{destination}: imported implementation was edited locally') + elif previous: + raise ValueError(f'{destination}: imported implementation was deleted locally') + core.add_write(plan, destination, contents[destination], mode=claim['mode']) + records[destination] = claim + repo = repository(plan.source_root) + import_key = repository_identity(repo) + '::' + plan.source_root.relative_to(repo).as_posix() + '::' + plan.page + imports = manifest.setdefault('imports', {}) + previous_files = imports.get(import_key, {}).get('files', []) + for destination in previous_files: + if destination not in claims: + plan.warnings.append(f'{destination}: removed upstream; cleanup candidate retained locally') + # The graph path is repository-relative so the manifest stays the same across checkouts. + imports[import_key] = {'source_graph': plan.source_root.relative_to(repo).as_posix(), 'page': plan.page, 'files': sorted(set(previous_files) | set(claims))} + if plan.pages or claims or manifest_path.exists(): + core.add_write(plan, MANIFEST, (json.dumps(manifest, indent=2, sort_keys=True) + '\n').encode(), mode=0o644) diff --git a/gitp-garden/mise-tasks/logseq/entity/proxy/page/sync b/gitp-garden/mise-tasks/logseq/entity/proxy/page/sync index 0a9de95..508bfb5 100755 --- a/gitp-garden/mise-tasks/logseq/entity/proxy/page/sync +++ b/gitp-garden/mise-tasks/logseq/entity/proxy/page/sync @@ -8,7 +8,11 @@ #USAGE flag "--follow-embeds" help="Also sync pages the page embeds, recursively" #USAGE flag "--apply" help="Apply the previewed import" #USAGE flag "--recover" help="Roll back an interrupted import, then exit" -"""Task reference: [[Logseq/Entity/Proxy/Page/mise/Task/sync]].""" +"""Task reference: [[Logseq/Entity/Proxy/Page/mise/Task/sync]]. + +Illustrated guide: mise run logseq:entity:proxy:page:docs:serve +Source: docs/index.html beside this entrypoint. +""" import argparse import os from pathlib import Path @@ -47,13 +51,13 @@ def main(): plan = build_page_plan(options.source, options.destination, options.page, options.codeforge_url, options.follow_embeds) try: - import companions + import task_imports except ModuleNotFoundError as error: - if error.name != 'companions': + if error.name != 'task_imports': raise - raise SyncError('Missing companion importer lib/companions.py; restore the task implementation before syncing') from error + raise SyncError('Missing task importer lib/task_imports.py; restore the task implementation before syncing') from error else: - companions.extend_plan(plan) + task_imports.extend_plan(plan) print('\n'.join(plan.details)) for warning in plan.warnings: print('Warning: ' + warning) diff --git a/gitp-garden/pages/GitP___A___Session___24___11___19-Tue.md b/gitp-garden/pages/GitP___A___Session___24___11___19-Tue.md index 981006e..3b00b45 100644 --- a/gitp-garden/pages/GitP___A___Session___24___11___19-Tue.md +++ b/gitp-garden/pages/GitP___A___Session___24___11___19-Tue.md @@ -5,8 +5,8 @@ created-by:: [[Person/codekiln]] date-created:: [[2024-11-19 Tue]] logseq-entity:: [[Logseq/Entity/Podcast/Episode]], [[Logseq/Entity/Proxy/Page]] logseq-proxy-url:: logseq://graph/logseq-encode-garden?page=GitP%2FA%2FSession%2F24%2F11%2F19-Tue -logseq-proxy-codeforge-url:: https://github.com/codekiln/logseq-encode-garden/blob/codex%2F197-listener-episode-pages/pages/GitP___A___Session___24___11___19-Tue.md -logseq-proxy-last-sync-date:: [[2026-10-06]] +logseq-proxy-codeforge-url:: https://github.com/codekiln/logseq-encode-garden/blob/main/pages/GitP___A___Session___24___11___19-Tue.md +logseq-proxy-last-sync-date:: [[2026-10-07]] - # GitP.24.11.19 - A MicroFreak session recorded on November 19, 2024. - ![GitP.24.11.19 artwork](https://s3.us-east-005.backblazeb2.com/logseq-encode-garden/GitP___A___Session___24___11___19-Tue___Asset___Artwork___Overview.gif) diff --git a/gitp-garden/pages/GitP___A___Session___24___11___19-Tue___Asset___Artwork___Overview___gif.md b/gitp-garden/pages/GitP___A___Session___24___11___19-Tue___Asset___Artwork___Overview___gif.md index 7a756bb..1b601ce 100644 --- a/gitp-garden/pages/GitP___A___Session___24___11___19-Tue___Asset___Artwork___Overview___gif.md +++ b/gitp-garden/pages/GitP___A___Session___24___11___19-Tue___Asset___Artwork___Overview___gif.md @@ -1,6 +1,6 @@ logseq-entity:: [[Logseq/Entity/Asset/B2]], [[Logseq/Entity/Proxy/Page]] logseq-proxy-url:: logseq://graph/logseq-encode-garden?page=GitP%2FA%2FSession%2F24%2F11%2F19-Tue%2FAsset%2FArtwork%2FOverview%2Fgif logseq-proxy-codeforge-url:: https://github.com/codekiln/logseq-encode-garden/blob/main/pages/GitP___A___Session___24___11___19-Tue___Asset___Artwork___Overview___gif.md -logseq-proxy-last-sync-date:: [[2026-10-06]] +logseq-proxy-last-sync-date:: [[2026-10-07]] - # GitP.24.11.19 artwork - ![GitP.24.11.19 artwork](https://s3.us-east-005.backblazeb2.com/logseq-encode-garden/GitP___A___Session___24___11___19-Tue___Asset___Artwork___Overview.gif) diff --git a/gitp-garden/pages/GitP___A___Session___24___11___19-Tue___Asset___Preset___A___mfpz.md b/gitp-garden/pages/GitP___A___Session___24___11___19-Tue___Asset___Preset___A___mfpz.md index 86c335f..f9f6167 100644 --- a/gitp-garden/pages/GitP___A___Session___24___11___19-Tue___Asset___Preset___A___mfpz.md +++ b/gitp-garden/pages/GitP___A___Session___24___11___19-Tue___Asset___Preset___A___mfpz.md @@ -1,6 +1,6 @@ logseq-entity:: [[Logseq/Entity/Asset/B2]], [[Logseq/Entity/Proxy/Page]] logseq-proxy-url:: logseq://graph/logseq-encode-garden?page=GitP%2FA%2FSession%2F24%2F11%2F19-Tue%2FAsset%2FPreset%2FA%2Fmfpz logseq-proxy-codeforge-url:: https://github.com/codekiln/logseq-encode-garden/blob/main/pages/GitP___A___Session___24___11___19-Tue___Asset___Preset___A___mfpz.md -logseq-proxy-last-sync-date:: [[2026-10-06]] +logseq-proxy-last-sync-date:: [[2026-10-07]] - # GitP.24.11.19 preset A - [Download MicroFreak preset A](https://s3.us-east-005.backblazeb2.com/logseq-encode-garden/GitP___A___Session___24___11___19-Tue___Asset___Preset___A.mfpz) diff --git a/gitp-garden/pages/GitP___A___Session___24___11___19-Tue___Asset___Preset___B___mfpz.md b/gitp-garden/pages/GitP___A___Session___24___11___19-Tue___Asset___Preset___B___mfpz.md index 939c145..27c5323 100644 --- a/gitp-garden/pages/GitP___A___Session___24___11___19-Tue___Asset___Preset___B___mfpz.md +++ b/gitp-garden/pages/GitP___A___Session___24___11___19-Tue___Asset___Preset___B___mfpz.md @@ -1,6 +1,6 @@ logseq-entity:: [[Logseq/Entity/Asset/B2]], [[Logseq/Entity/Proxy/Page]] logseq-proxy-url:: logseq://graph/logseq-encode-garden?page=GitP%2FA%2FSession%2F24%2F11%2F19-Tue%2FAsset%2FPreset%2FB%2Fmfpz logseq-proxy-codeforge-url:: https://github.com/codekiln/logseq-encode-garden/blob/main/pages/GitP___A___Session___24___11___19-Tue___Asset___Preset___B___mfpz.md -logseq-proxy-last-sync-date:: [[2026-10-06]] +logseq-proxy-last-sync-date:: [[2026-10-07]] - # GitP.24.11.19 preset B - [Download MicroFreak preset B](https://s3.us-east-005.backblazeb2.com/logseq-encode-garden/GitP___A___Session___24___11___19-Tue___Asset___Preset___B.mfpz) diff --git a/gitp-garden/pages/GitP___A___Session___24___11___19-Tue___Asset___Preset___C___mfpz.md b/gitp-garden/pages/GitP___A___Session___24___11___19-Tue___Asset___Preset___C___mfpz.md index c7b4aa7..b5ae48a 100644 --- a/gitp-garden/pages/GitP___A___Session___24___11___19-Tue___Asset___Preset___C___mfpz.md +++ b/gitp-garden/pages/GitP___A___Session___24___11___19-Tue___Asset___Preset___C___mfpz.md @@ -1,6 +1,6 @@ logseq-entity:: [[Logseq/Entity/Asset/B2]], [[Logseq/Entity/Proxy/Page]] logseq-proxy-url:: logseq://graph/logseq-encode-garden?page=GitP%2FA%2FSession%2F24%2F11%2F19-Tue%2FAsset%2FPreset%2FC%2Fmfpz logseq-proxy-codeforge-url:: https://github.com/codekiln/logseq-encode-garden/blob/main/pages/GitP___A___Session___24___11___19-Tue___Asset___Preset___C___mfpz.md -logseq-proxy-last-sync-date:: [[2026-10-06]] +logseq-proxy-last-sync-date:: [[2026-10-07]] - # GitP.24.11.19 preset C - [Download MicroFreak preset C](https://s3.us-east-005.backblazeb2.com/logseq-encode-garden/GitP___A___Session___24___11___19-Tue___Asset___Preset___C.mfpz) diff --git a/gitp-garden/pages/GitP___A___Session___24___11___19-Tue___Asset___Synth___Full___mp3.md b/gitp-garden/pages/GitP___A___Session___24___11___19-Tue___Asset___Synth___Full___mp3.md index 746dca9..8dabd30 100644 --- a/gitp-garden/pages/GitP___A___Session___24___11___19-Tue___Asset___Synth___Full___mp3.md +++ b/gitp-garden/pages/GitP___A___Session___24___11___19-Tue___Asset___Synth___Full___mp3.md @@ -2,6 +2,6 @@ duration-seconds:: 422.752313 logseq-entity:: [[Logseq/Entity/Asset/B2]], [[Logseq/Entity/Proxy/Page]] logseq-proxy-url:: logseq://graph/logseq-encode-garden?page=GitP%2FA%2FSession%2F24%2F11%2F19-Tue%2FAsset%2FSynth%2FFull%2Fmp3 logseq-proxy-codeforge-url:: https://github.com/codekiln/logseq-encode-garden/blob/main/pages/GitP___A___Session___24___11___19-Tue___Asset___Synth___Full___mp3.md -logseq-proxy-last-sync-date:: [[2026-10-06]] +logseq-proxy-last-sync-date:: [[2026-10-07]] - # GitP.24.11.19 MP3 - ![GitP.24.11.19 — episode recording](https://s3.us-east-005.backblazeb2.com/logseq-encode-garden/GitP___A___Session___24___11___19-Tue___Asset___Synth___Full.mp3) diff --git a/gitp-garden/pages/GitP___A___Session___24___12___04-Wed.md b/gitp-garden/pages/GitP___A___Session___24___12___04-Wed.md index bfd38ed..0ffeedc 100644 --- a/gitp-garden/pages/GitP___A___Session___24___12___04-Wed.md +++ b/gitp-garden/pages/GitP___A___Session___24___12___04-Wed.md @@ -5,8 +5,8 @@ created-by:: [[Person/codekiln]] date-created:: [[2024-12-04 Wed]] logseq-entity:: [[Logseq/Entity/Podcast/Episode]], [[Logseq/Entity/Proxy/Page]] logseq-proxy-url:: logseq://graph/logseq-encode-garden?page=GitP%2FA%2FSession%2F24%2F12%2F04-Wed -logseq-proxy-codeforge-url:: https://github.com/codekiln/logseq-encode-garden/blob/codex%2F197-listener-episode-pages/pages/GitP___A___Session___24___12___04-Wed.md -logseq-proxy-last-sync-date:: [[2026-10-06]] +logseq-proxy-codeforge-url:: https://github.com/codekiln/logseq-encode-garden/blob/main/pages/GitP___A___Session___24___12___04-Wed.md +logseq-proxy-last-sync-date:: [[2026-10-07]] - # GitP.24.12.04 - A MicroFreak session recorded on December 4, 2024. - ![GitP.24.12.04 artwork](https://s3.us-east-005.backblazeb2.com/logseq-encode-garden/GitP___A___Session___24___12___04-Wed___Asset___Artwork___Overview.gif) diff --git a/gitp-garden/pages/GitP___A___Session___24___12___04-Wed___Asset___Artwork___Overview___gif.md b/gitp-garden/pages/GitP___A___Session___24___12___04-Wed___Asset___Artwork___Overview___gif.md index fd201a3..56d4d9c 100644 --- a/gitp-garden/pages/GitP___A___Session___24___12___04-Wed___Asset___Artwork___Overview___gif.md +++ b/gitp-garden/pages/GitP___A___Session___24___12___04-Wed___Asset___Artwork___Overview___gif.md @@ -1,6 +1,6 @@ logseq-entity:: [[Logseq/Entity/Asset/B2]], [[Logseq/Entity/Proxy/Page]] logseq-proxy-url:: logseq://graph/logseq-encode-garden?page=GitP%2FA%2FSession%2F24%2F12%2F04-Wed%2FAsset%2FArtwork%2FOverview%2Fgif logseq-proxy-codeforge-url:: https://github.com/codekiln/logseq-encode-garden/blob/main/pages/GitP___A___Session___24___12___04-Wed___Asset___Artwork___Overview___gif.md -logseq-proxy-last-sync-date:: [[2026-10-06]] +logseq-proxy-last-sync-date:: [[2026-10-07]] - # GitP.24.12.04 artwork - ![GitP.24.12.04 artwork](https://s3.us-east-005.backblazeb2.com/logseq-encode-garden/GitP___A___Session___24___12___04-Wed___Asset___Artwork___Overview.gif) diff --git a/gitp-garden/pages/GitP___A___Session___24___12___04-Wed___Asset___MIDI___Microfreak___mid.md b/gitp-garden/pages/GitP___A___Session___24___12___04-Wed___Asset___MIDI___Microfreak___mid.md index 65e67a5..e6b4f2c 100644 --- a/gitp-garden/pages/GitP___A___Session___24___12___04-Wed___Asset___MIDI___Microfreak___mid.md +++ b/gitp-garden/pages/GitP___A___Session___24___12___04-Wed___Asset___MIDI___Microfreak___mid.md @@ -1,6 +1,6 @@ logseq-entity:: [[Logseq/Entity/Asset/B2]], [[Logseq/Entity/Proxy/Page]] logseq-proxy-url:: logseq://graph/logseq-encode-garden?page=GitP%2FA%2FSession%2F24%2F12%2F04-Wed%2FAsset%2FMIDI%2FMicrofreak%2Fmid logseq-proxy-codeforge-url:: https://github.com/codekiln/logseq-encode-garden/blob/main/pages/GitP___A___Session___24___12___04-Wed___Asset___MIDI___Microfreak___mid.md -logseq-proxy-last-sync-date:: [[2026-10-06]] +logseq-proxy-last-sync-date:: [[2026-10-07]] - # GitP.24.12.04 MicroFreak MIDI - [Download MicroFreak MIDI](https://s3.us-east-005.backblazeb2.com/logseq-encode-garden/GitP___A___Session___24___12___04-Wed___Asset___MIDI___Microfreak.mid) diff --git a/gitp-garden/pages/GitP___A___Session___24___12___04-Wed___Asset___Preset___A___mfpz.md b/gitp-garden/pages/GitP___A___Session___24___12___04-Wed___Asset___Preset___A___mfpz.md index a00e432..4f6bdbe 100644 --- a/gitp-garden/pages/GitP___A___Session___24___12___04-Wed___Asset___Preset___A___mfpz.md +++ b/gitp-garden/pages/GitP___A___Session___24___12___04-Wed___Asset___Preset___A___mfpz.md @@ -1,6 +1,6 @@ logseq-entity:: [[Logseq/Entity/Asset/B2]], [[Logseq/Entity/Proxy/Page]] logseq-proxy-url:: logseq://graph/logseq-encode-garden?page=GitP%2FA%2FSession%2F24%2F12%2F04-Wed%2FAsset%2FPreset%2FA%2Fmfpz logseq-proxy-codeforge-url:: https://github.com/codekiln/logseq-encode-garden/blob/main/pages/GitP___A___Session___24___12___04-Wed___Asset___Preset___A___mfpz.md -logseq-proxy-last-sync-date:: [[2026-10-06]] +logseq-proxy-last-sync-date:: [[2026-10-07]] - # GitP.24.12.04 preset A - [Download MicroFreak preset A](https://s3.us-east-005.backblazeb2.com/logseq-encode-garden/GitP___A___Session___24___12___04-Wed___Asset___Preset___A.mfpz) diff --git a/gitp-garden/pages/GitP___A___Session___24___12___04-Wed___Asset___Preset___B___mfpz.md b/gitp-garden/pages/GitP___A___Session___24___12___04-Wed___Asset___Preset___B___mfpz.md index b8face8..4bfd0ee 100644 --- a/gitp-garden/pages/GitP___A___Session___24___12___04-Wed___Asset___Preset___B___mfpz.md +++ b/gitp-garden/pages/GitP___A___Session___24___12___04-Wed___Asset___Preset___B___mfpz.md @@ -1,6 +1,6 @@ logseq-entity:: [[Logseq/Entity/Asset/B2]], [[Logseq/Entity/Proxy/Page]] logseq-proxy-url:: logseq://graph/logseq-encode-garden?page=GitP%2FA%2FSession%2F24%2F12%2F04-Wed%2FAsset%2FPreset%2FB%2Fmfpz logseq-proxy-codeforge-url:: https://github.com/codekiln/logseq-encode-garden/blob/main/pages/GitP___A___Session___24___12___04-Wed___Asset___Preset___B___mfpz.md -logseq-proxy-last-sync-date:: [[2026-10-06]] +logseq-proxy-last-sync-date:: [[2026-10-07]] - # GitP.24.12.04 preset B - [Download MicroFreak preset B](https://s3.us-east-005.backblazeb2.com/logseq-encode-garden/GitP___A___Session___24___12___04-Wed___Asset___Preset___B.mfpz) diff --git a/gitp-garden/pages/GitP___A___Session___24___12___04-Wed___Asset___Preset___C___mfpz.md b/gitp-garden/pages/GitP___A___Session___24___12___04-Wed___Asset___Preset___C___mfpz.md index 37706bc..cb96481 100644 --- a/gitp-garden/pages/GitP___A___Session___24___12___04-Wed___Asset___Preset___C___mfpz.md +++ b/gitp-garden/pages/GitP___A___Session___24___12___04-Wed___Asset___Preset___C___mfpz.md @@ -1,6 +1,6 @@ logseq-entity:: [[Logseq/Entity/Asset/B2]], [[Logseq/Entity/Proxy/Page]] logseq-proxy-url:: logseq://graph/logseq-encode-garden?page=GitP%2FA%2FSession%2F24%2F12%2F04-Wed%2FAsset%2FPreset%2FC%2Fmfpz logseq-proxy-codeforge-url:: https://github.com/codekiln/logseq-encode-garden/blob/main/pages/GitP___A___Session___24___12___04-Wed___Asset___Preset___C___mfpz.md -logseq-proxy-last-sync-date:: [[2026-10-06]] +logseq-proxy-last-sync-date:: [[2026-10-07]] - # GitP.24.12.04 preset C - [Download MicroFreak preset C](https://s3.us-east-005.backblazeb2.com/logseq-encode-garden/GitP___A___Session___24___12___04-Wed___Asset___Preset___C.mfpz) diff --git a/gitp-garden/pages/GitP___A___Session___24___12___04-Wed___Asset___Preset___D___mfpz.md b/gitp-garden/pages/GitP___A___Session___24___12___04-Wed___Asset___Preset___D___mfpz.md index 32891bd..c48f853 100644 --- a/gitp-garden/pages/GitP___A___Session___24___12___04-Wed___Asset___Preset___D___mfpz.md +++ b/gitp-garden/pages/GitP___A___Session___24___12___04-Wed___Asset___Preset___D___mfpz.md @@ -1,6 +1,6 @@ logseq-entity:: [[Logseq/Entity/Asset/B2]], [[Logseq/Entity/Proxy/Page]] logseq-proxy-url:: logseq://graph/logseq-encode-garden?page=GitP%2FA%2FSession%2F24%2F12%2F04-Wed%2FAsset%2FPreset%2FD%2Fmfpz logseq-proxy-codeforge-url:: https://github.com/codekiln/logseq-encode-garden/blob/main/pages/GitP___A___Session___24___12___04-Wed___Asset___Preset___D___mfpz.md -logseq-proxy-last-sync-date:: [[2026-10-06]] +logseq-proxy-last-sync-date:: [[2026-10-07]] - # GitP.24.12.04 preset D - [Download MicroFreak preset D](https://s3.us-east-005.backblazeb2.com/logseq-encode-garden/GitP___A___Session___24___12___04-Wed___Asset___Preset___D.mfpz) diff --git a/gitp-garden/pages/GitP___A___Session___24___12___04-Wed___Asset___Synth___Full___mp3.md b/gitp-garden/pages/GitP___A___Session___24___12___04-Wed___Asset___Synth___Full___mp3.md index 1d6f316..397fc10 100644 --- a/gitp-garden/pages/GitP___A___Session___24___12___04-Wed___Asset___Synth___Full___mp3.md +++ b/gitp-garden/pages/GitP___A___Session___24___12___04-Wed___Asset___Synth___Full___mp3.md @@ -2,6 +2,6 @@ duration-seconds:: 2872.065669 logseq-entity:: [[Logseq/Entity/Asset/B2]], [[Logseq/Entity/Proxy/Page]] logseq-proxy-url:: logseq://graph/logseq-encode-garden?page=GitP%2FA%2FSession%2F24%2F12%2F04-Wed%2FAsset%2FSynth%2FFull%2Fmp3 logseq-proxy-codeforge-url:: https://github.com/codekiln/logseq-encode-garden/blob/main/pages/GitP___A___Session___24___12___04-Wed___Asset___Synth___Full___mp3.md -logseq-proxy-last-sync-date:: [[2026-10-06]] +logseq-proxy-last-sync-date:: [[2026-10-07]] - # GitP.24.12.04 MP3 - ![GitP.24.12.04 — episode recording](https://s3.us-east-005.backblazeb2.com/logseq-encode-garden/GitP___A___Session___24___12___04-Wed___Asset___Synth___Full.mp3) diff --git a/gitp-garden/pages/GitP___A___Session___26___09___24-Thu.md b/gitp-garden/pages/GitP___A___Session___26___09___24-Thu.md index a1a3ea9..a263a0f 100644 --- a/gitp-garden/pages/GitP___A___Session___26___09___24-Thu.md +++ b/gitp-garden/pages/GitP___A___Session___26___09___24-Thu.md @@ -5,8 +5,8 @@ created-by:: [[Person/codekiln]] date-created:: [[2026-09-24 Thu]] logseq-entity:: [[Logseq/Entity/Podcast/Episode]], [[Logseq/Entity/Proxy/Page]] logseq-proxy-url:: logseq://graph/logseq-encode-garden?page=GitP%2FA%2FSession%2F26%2F09%2F24-Thu -logseq-proxy-codeforge-url:: https://github.com/codekiln/logseq-encode-garden/blob/codex%2F197-listener-episode-pages/pages/GitP___A___Session___26___09___24-Thu.md -logseq-proxy-last-sync-date:: [[2026-10-06]] +logseq-proxy-codeforge-url:: https://github.com/codekiln/logseq-encode-garden/blob/main/pages/GitP___A___Session___26___09___24-Thu.md +logseq-proxy-last-sync-date:: [[2026-10-07]] - # GitP.26.09.24 - A MicroFreak and Launchpad session beginning with two-operator FM on an initialized patch. - ![GitP.26.09.24 — episode recording](https://s3.us-east-005.backblazeb2.com/logseq-encode-garden/GitP___A___Session___26___09___24-Thu___Asset___Synth___Full.mp3) diff --git a/gitp-garden/pages/GitP___A___Session___26___09___24-Thu___Asset___Synth___Full___mp3.md b/gitp-garden/pages/GitP___A___Session___26___09___24-Thu___Asset___Synth___Full___mp3.md index 7db7024..66c3931 100644 --- a/gitp-garden/pages/GitP___A___Session___26___09___24-Thu___Asset___Synth___Full___mp3.md +++ b/gitp-garden/pages/GitP___A___Session___26___09___24-Thu___Asset___Synth___Full___mp3.md @@ -2,6 +2,6 @@ duration-seconds:: 757.761066 logseq-entity:: [[Logseq/Entity/Asset/B2]], [[Logseq/Entity/Proxy/Page]] logseq-proxy-url:: logseq://graph/logseq-encode-garden?page=GitP%2FA%2FSession%2F26%2F09%2F24-Thu%2FAsset%2FSynth%2FFull%2Fmp3 logseq-proxy-codeforge-url:: https://github.com/codekiln/logseq-encode-garden/blob/main/pages/GitP___A___Session___26___09___24-Thu___Asset___Synth___Full___mp3.md -logseq-proxy-last-sync-date:: [[2026-10-06]] +logseq-proxy-last-sync-date:: [[2026-10-07]] - # GitP.26.09.24 MP3 - ![GitP.26.09.24 — episode recording](https://s3.us-east-005.backblazeb2.com/logseq-encode-garden/GitP___A___Session___26___09___24-Thu___Asset___Synth___Full.mp3) diff --git a/gitp-garden/pages/GitP___A___Session___26___09___25-Fri.md b/gitp-garden/pages/GitP___A___Session___26___09___25-Fri.md index 8426db3..a7c832f 100644 --- a/gitp-garden/pages/GitP___A___Session___26___09___25-Fri.md +++ b/gitp-garden/pages/GitP___A___Session___26___09___25-Fri.md @@ -5,8 +5,8 @@ created-by:: [[Person/codekiln]] date-created:: [[2026-09-25 Fri]] logseq-entity:: [[Logseq/Entity/Podcast/Episode]], [[Logseq/Entity/Proxy/Page]] logseq-proxy-url:: logseq://graph/logseq-encode-garden?page=GitP%2FA%2FSession%2F26%2F09%2F25-Fri -logseq-proxy-codeforge-url:: https://github.com/codekiln/logseq-encode-garden/blob/codex%2F197-listener-episode-pages/pages/GitP___A___Session___26___09___25-Fri.md -logseq-proxy-last-sync-date:: [[2026-10-06]] +logseq-proxy-codeforge-url:: https://github.com/codekiln/logseq-encode-garden/blob/main/pages/GitP___A___Session___26___09___25-Fri.md +logseq-proxy-last-sync-date:: [[2026-10-07]] - # GitP.26.09.25 - MicroFreak SAWX and WaveUser preset 1910, with a Novation Launchpad sequence. - ![GitP.26.09.25 — episode recording](https://s3.us-east-005.backblazeb2.com/logseq-encode-garden/GitP___A___Session___26___09___25-Fri___Asset___Synth___Full.mp3) diff --git a/gitp-garden/pages/GitP___A___Session___26___09___25-Fri___Asset___Synth___Full___mp3.md b/gitp-garden/pages/GitP___A___Session___26___09___25-Fri___Asset___Synth___Full___mp3.md index 2ccd0e5..a9f38fd 100644 --- a/gitp-garden/pages/GitP___A___Session___26___09___25-Fri___Asset___Synth___Full___mp3.md +++ b/gitp-garden/pages/GitP___A___Session___26___09___25-Fri___Asset___Synth___Full___mp3.md @@ -2,6 +2,6 @@ duration-seconds:: 982.009977 logseq-entity:: [[Logseq/Entity/Asset/B2]], [[Logseq/Entity/Proxy/Page]] logseq-proxy-url:: logseq://graph/logseq-encode-garden?page=GitP%2FA%2FSession%2F26%2F09%2F25-Fri%2FAsset%2FSynth%2FFull%2Fmp3 logseq-proxy-codeforge-url:: https://github.com/codekiln/logseq-encode-garden/blob/main/pages/GitP___A___Session___26___09___25-Fri___Asset___Synth___Full___mp3.md -logseq-proxy-last-sync-date:: [[2026-10-06]] +logseq-proxy-last-sync-date:: [[2026-10-07]] - # GitP.26.09.25 MP3 - ![GitP.26.09.25 — episode recording](https://s3.us-east-005.backblazeb2.com/logseq-encode-garden/GitP___A___Session___26___09___25-Fri___Asset___Synth___Full.mp3) diff --git a/gitp-garden/pages/Logseq___Entity___Asset___B2.md b/gitp-garden/pages/Logseq___Entity___Asset___B2.md index 4ce3e9b..dfdd7a8 100644 --- a/gitp-garden/pages/Logseq___Entity___Asset___B2.md +++ b/gitp-garden/pages/Logseq___Entity___Asset___B2.md @@ -1,7 +1,7 @@ logseq-entity:: [[Logseq/Entity/Definition]], [[Logseq/Entity/Proxy/Page]] logseq-proxy-url:: logseq://graph/logseq-encode-garden?page=Logseq%2FEntity%2FAsset%2FB2 logseq-proxy-codeforge-url:: https://github.com/codekiln/logseq-encode-garden/blob/main/pages/Logseq___Entity___Asset___B2.md -logseq-proxy-last-sync-date:: [[2026-10-06]] +logseq-proxy-last-sync-date:: [[2026-10-07]] - # Backblaze B2 Asset - In this garden, **Backblaze B2 Asset** pages represent files stored in Backblaze B2, following [[Logseq/Entity/Asset]] for filenames, ownership, and page contents. - ## Storage location diff --git a/gitp-garden/pages/Logseq___Entity___Definition.md b/gitp-garden/pages/Logseq___Entity___Definition.md index 60610ba..1733690 100644 --- a/gitp-garden/pages/Logseq___Entity___Definition.md +++ b/gitp-garden/pages/Logseq___Entity___Definition.md @@ -1,8 +1,8 @@ logseq-entity:: [[Logseq/Entity/Definition]], [[Logseq/Entity/Proxy/Page]] see-also:: [[Logseq/Entity/Definition/Discussion]] logseq-proxy-url:: logseq://graph/logseq-encode-garden?page=Logseq%2FEntity%2FDefinition -logseq-proxy-codeforge-url:: https://github.com/codekiln/logseq-encode-garden/blob/codex%2F189-proxy-worktree-identity/pages/Logseq___Entity___Definition.md -logseq-proxy-last-sync-date:: [[2026-10-06]] +logseq-proxy-codeforge-url:: https://github.com/codekiln/logseq-encode-garden/blob/codex%2F202-proxy-task-import-docs/pages/Logseq___Entity___Definition.md +logseq-proxy-last-sync-date:: [[2026-10-07]] - # Entity Definition - Each Entity Definition page describes a type of real-world entity that may be tracked in a page [[Knowledge Garden]] page. Entity here means something roughly analagous - ## [[Logseq/Entity/Definition/Discussion]] diff --git a/gitp-garden/pages/Logseq___Entity___Mise___Task.md b/gitp-garden/pages/Logseq___Entity___Mise___Task.md index 8b3ea2a..65a6d3c 100644 --- a/gitp-garden/pages/Logseq___Entity___Mise___Task.md +++ b/gitp-garden/pages/Logseq___Entity___Mise___Task.md @@ -1,8 +1,8 @@ logseq-entity:: [[Logseq/Entity/Definition]], [[Logseq/Entity/Proxy/Page]] see-also:: [[mise/Task]], [[Logseq/Entity/CLI/Command]], [[Logseq/Entity/Diataxis/How To]] logseq-proxy-url:: logseq://graph/logseq-encode-garden?page=Logseq%2FEntity%2FMise%2FTask -logseq-proxy-codeforge-url:: https://github.com/codekiln/logseq-encode-garden/blob/codex%2F189-proxy-worktree-identity/pages/Logseq___Entity___Mise___Task.md -logseq-proxy-last-sync-date:: [[2026-10-06]] +logseq-proxy-codeforge-url:: https://github.com/codekiln/logseq-encode-garden/blob/codex%2F202-proxy-task-import-docs/pages/Logseq___Entity___Mise___Task.md +logseq-proxy-last-sync-date:: [[2026-10-07]] - # Mise Task - In this garden, **Mise Task** pages model named jobs supplied by a repository or configuration scope and invoked through [[mise]]. - ## Identity diff --git a/gitp-garden/pages/Logseq___Entity___Podcast___Episode.md b/gitp-garden/pages/Logseq___Entity___Podcast___Episode.md index b46a769..c18135c 100644 --- a/gitp-garden/pages/Logseq___Entity___Podcast___Episode.md +++ b/gitp-garden/pages/Logseq___Entity___Podcast___Episode.md @@ -1,8 +1,8 @@ logseq-entity:: [[Logseq/Entity/Definition]], [[Logseq/Entity/Proxy/Page]] entity-proxy-destination-properties:: podcast-guid, podcast-published-at logseq-proxy-url:: logseq://graph/logseq-encode-garden?page=Logseq%2FEntity%2FPodcast%2FEpisode -logseq-proxy-codeforge-url:: https://github.com/codekiln/logseq-encode-garden/blob/codex%2F197-listener-episode-pages/pages/Logseq___Entity___Podcast___Episode.md -logseq-proxy-last-sync-date:: [[2026-10-06]] +logseq-proxy-codeforge-url:: https://github.com/codekiln/logseq-encode-garden/blob/main/pages/Logseq___Entity___Podcast___Episode.md +logseq-proxy-last-sync-date:: [[2026-10-07]] - # Podcast Episode - In this garden, **Podcast Episode** pages model one episode of a [[Logseq/Entity/Podcast]], captured as listening notes or a recording prepared for publication. @@ -35,7 +35,7 @@ logseq-proxy-last-sync-date:: [[2026-10-06]] - ## Page shape - Logseq Flavored Markdown. - The first body block is the H1 heading with the episode title linked to the episode when a URL is known: `- # [Episode Title](https://example.com/episode)`. Without a URL, use a plain `- # Episode Title`. - - A producer-owned session opens with an optional short description, artwork when available, and a directly playable MP3 recording. Artwork and audio use Markdown media embeds with the asset URLs: `![Episode artwork](https://example.com/artwork.gif)` and `![Episode recording](https://example.com/recording.mp3)`. + - A producer-owned session opens with an optional short description, artwork when available, and a directly playable MP3 recording. The recording’s [[Logseq/Entity/Asset]] page holds its file metadata. Artwork and audio use Markdown media embeds with the asset URLs: `![Episode artwork](https://example.com/artwork.gif)` and `![Episode recording](https://example.com/recording.mp3)`. - Downloadable MicroFreak patches use labeled Markdown links to the files, such as `[Download MicroFreak preset A](https://example.com/preset-A.mfpz)`, so listeners can download them from the episode page. Episode media and download details use the direct URLs rather than asset page embeds or asset wikilinks. - Session notes follow the media and downloads. Technical notes may be collapsed so the recording and patches remain immediately visible. - In the Gitpa publishing garden, the visible episode properties are `logseq-entity` and `date-created`. diff --git a/gitp-garden/pages/Logseq___Entity___Proxy___Page.md b/gitp-garden/pages/Logseq___Entity___Proxy___Page.md index 748c219..9279d19 100644 --- a/gitp-garden/pages/Logseq___Entity___Proxy___Page.md +++ b/gitp-garden/pages/Logseq___Entity___Proxy___Page.md @@ -1,10 +1,10 @@ alias:: [[Proxy Page]], [[Logseq Proxy Page]] -entity-tasks:: [[Logseq/Entity/Proxy/Page/mise/Task/sync]] +entity-tasks:: [[Logseq/Entity/Proxy/Page/mise/Task/sync]], [[Logseq/Entity/Proxy/Page/mise/Task/docs/serve]] logseq-entity:: [[Logseq/Entity/Definition]], [[Logseq/Entity/Proxy/Page]] entity-proxy-destination-properties:: public logseq-proxy-url:: logseq://graph/logseq-encode-garden?page=Logseq%2FEntity%2FProxy%2FPage -logseq-proxy-codeforge-url:: https://github.com/codekiln/logseq-encode-garden/blob/codex%2F189-proxy-worktree-identity/pages/Logseq___Entity___Proxy___Page.md -logseq-proxy-last-sync-date:: [[2026-10-06]] +logseq-proxy-codeforge-url:: https://github.com/codekiln/logseq-encode-garden/blob/codex%2F202-proxy-task-import-docs/pages/Logseq___Entity___Proxy___Page.md +logseq-proxy-last-sync-date:: [[2026-10-07]] - # Proxy Page - In this garden, **Proxy Page** marks a page whose body is mirrored from a page in another [[Logseq/Garden]], so one garden can read a page that lives in another without that page being moved or duplicated by hand. See [[Logseq/Idea/Proxy]] for the motivation. - ## What counts as an instance @@ -58,14 +58,23 @@ logseq-proxy-last-sync-date:: [[2026-10-06]] - **Assets:** every `../assets/` the source body links to is copied to the same `assets/` here, replacing what is there. A missing source asset is reported and the sync goes on. - **Embeds:** with `--follow-embeds`, each page embedded with the `embed` macro is synced as a proxy too, recursively, so a page and the pages it embeds sync in one batch. A missing embedded page is reported and the sync goes on. - **Report:** the source path, the destination path, the proxy key values written, whether it was a first copy or a re-sync, the properties added, updated or removed, and the assets copied. + - ## Documentation + - [[Logseq/Entity/Proxy/Page/mise/Task/docs/serve]] opens the illustrated guide to adding and updating proxies, multiple source gardens, manifest ownership, Git tracking, and parallel imports. + - ~~~sh + mise run logseq:entity:proxy:page:docs:serve + ~~~ - ## Executable sync - [[Logseq/Entity/Proxy/Page/mise/Task/sync]] previews the page, entity definitions, companion task references, implementation files, and assets imported by a sync. `--apply` applies the previewed changes. - An instance's `logseq-entity::` links lead to its source entity definitions. Each definition's `entity-tasks::` declares companion task references, whose file mappings and task dependencies follow [[Logseq/Entity/Mise/Task]]. The sync visits shared and cyclic dependencies once. - - `.logseq-proxy/manifest.json` in the destination graph records source repository and graph root, logical page identity, source-to-destination file mappings, ownership, and last imported content hashes. - - The manifest retains the latest source companion declarations. When a proxy becomes the source for another garden, task discovery uses those declarations and resolves imported implementation paths through the source manifest. - Re-sync refreshes source changes where imported implementation files still match their recorded hashes. Local implementation edits, unowned destination files, and competing source claims produce conflicts before application. - Page properties and bodies refresh from the source per **Invariants** above. Files removed from upstream task mappings are reported as cleanup candidates and retained locally. - A preview reports logical entity definitions without files separately from missing declared tasks or implementation files. Missing source assets remain warnings; missing task requirements stop application. + - ## Import manifest + - `.logseq-proxy/manifest.json` in the destination graph records source repository and graph path, logical page identity, source-to-destination file mappings, ownership, and last imported content hashes and modes. It accompanies the imported pages and task files in version control. + - `files` records implementation ownership and the last import's hash and mode; `pages` records source identity for each logical page. `tasks` retains each task's identity and file mapping; `imports` records the implementation paths associated with each requested page. + - `declarations` retains the latest source entity and task properties. When a proxy becomes the source for another garden, task discovery uses those saved declarations and resolves imported implementation paths through the source manifest. + - A re-sync compares each imported implementation file with its recorded hash and mode before replacing it. Deleting the manifest loses that baseline; existing task files then appear unowned and require reconciliation before importing again. + - [The illustrated manifest explanation](../mise-tasks/logseq/entity/proxy/page/docs/index.html#manifest) describes the sections, declaration precedence, and update checks. [[Logseq/Entity/Mise/Task]] specifies the `source-link::` and `task-files::` declarations from which task imports are planned. - ## Examples in this garden - [[Book/ML with PyTorch and Scikit-Learn]] - [[Person/Thomas Parr/Book/2022/Active Inference]] (legacy name shape) \ No newline at end of file diff --git a/gitp-garden/pages/Logseq___Entity___Proxy___Page___mise___Task___docs___serve.md b/gitp-garden/pages/Logseq___Entity___Proxy___Page___mise___Task___docs___serve.md new file mode 100644 index 0000000..17722bd --- /dev/null +++ b/gitp-garden/pages/Logseq___Entity___Proxy___Page___mise___Task___docs___serve.md @@ -0,0 +1,35 @@ +logseq-entity:: [[Logseq/Entity/Mise/Task]], [[Logseq/Entity/Proxy/Page]] +task-owner:: [[Person/codekiln/GitHub/logseq-encode-garden]] +task-config-root:: . +task-name:: logseq:entity:proxy:page:docs:serve +task-entrypoint:: mise-tasks/logseq/entity/proxy/page/docs/serve +task-files:: {"mise-tasks/logseq/entity/proxy/page/docs/serve":"mise-tasks/logseq/entity/proxy/page/docs/serve","mise-tasks/logseq/entity/proxy/page/docs/index.html":"mise-tasks/logseq/entity/proxy/page/docs/index.html"} +source-link:: https://github.com/codekiln/logseq-encode-garden/blob/main/mise-tasks/logseq/entity/proxy/page/docs/serve +see-also:: [[Logseq/Entity/Proxy/Page]], [[Logseq/Entity/Proxy/Page/mise/Task/sync]] +logseq-proxy-url:: logseq://graph/logseq-encode-garden?page=Logseq%2FEntity%2FProxy%2FPage%2Fmise%2FTask%2Fdocs%2Fserve +logseq-proxy-codeforge-url:: https://github.com/codekiln/logseq-encode-garden/blob/codex%2F202-proxy-task-import-docs/pages/Logseq___Entity___Proxy___Page___mise___Task___docs___serve.md +logseq-proxy-last-sync-date:: [[2026-10-07]] +- # Open the Proxy Algorithm Guide + - Opens an illustrated guide to proxy imports, refreshes, multiple source gardens, manifest ownership, Git tracking, and parallel work. + - ## Invocation + - Runs from the garden checkout or a destination graph containing the imported docs task: + - ~~~sh + mise run logseq:entity:proxy:page:docs:serve + ~~~ + - `--port` selects the local port; `--no-open` serves the guide without launching the default browser: + - ~~~sh + mise run logseq:entity:proxy:page:docs:serve --port 8768 --no-open + ~~~ + - ## Inputs and outputs + - Serves the adjacent [HTML guide](../mise-tasks/logseq/entity/proxy/page/docs/index.html) on `127.0.0.1`. The guide includes diagrams, lifecycle tabs, interactive conflict examples, and links to the implementation. + - The task's file mapping includes the launcher and HTML so they travel with [[Logseq/Entity/Proxy/Page/mise/Task/sync]]. + - ## Side effects and access + - Opens the default browser unless `--no-open` is supplied. The server runs until Ctrl-C and creates no build output or log files. + - Mise supplies Python. The server uses Python's standard library and requires local access to the guide and an available localhost port. + - ## Failure and recovery + - An occupied port can be replaced with another `--port` value. A missing guide requires restoring the mapped HTML file. + - ## Source and help + - [Docs launcher](https://github.com/codekiln/logseq-encode-garden/blob/main/mise-tasks/logseq/entity/proxy/page/docs/serve). + - ~~~sh + mise run logseq:entity:proxy:page:docs:serve --help + ~~~ diff --git a/gitp-garden/pages/Logseq___Entity___Proxy___Page___mise___Task___sync.md b/gitp-garden/pages/Logseq___Entity___Proxy___Page___mise___Task___sync.md index 075fc50..7d86d00 100644 --- a/gitp-garden/pages/Logseq___Entity___Proxy___Page___mise___Task___sync.md +++ b/gitp-garden/pages/Logseq___Entity___Proxy___Page___mise___Task___sync.md @@ -3,12 +3,13 @@ task-owner:: [[Person/codekiln/GitHub/logseq-encode-garden]] task-config-root:: . task-name:: logseq:entity:proxy:page:sync task-entrypoint:: mise-tasks/logseq/entity/proxy/page/sync -task-files:: {"mise-tasks/logseq/entity/proxy/page/sync":"mise-tasks/logseq/entity/proxy/page/sync","mise-tasks/logseq/entity/proxy/page/lib/core.py":"mise-tasks/logseq/entity/proxy/page/lib/core.py","mise-tasks/logseq/entity/proxy/page/lib/companions.py":"mise-tasks/logseq/entity/proxy/page/lib/companions.py"} +task-files:: {"mise-tasks/logseq/entity/proxy/page/sync":"mise-tasks/logseq/entity/proxy/page/sync","mise-tasks/logseq/entity/proxy/page/lib/core.py":"mise-tasks/logseq/entity/proxy/page/lib/core.py","mise-tasks/logseq/entity/proxy/page/lib/task_imports.py":"mise-tasks/logseq/entity/proxy/page/lib/task_imports.py"} source-link:: https://github.com/codekiln/logseq-encode-garden/blob/main/mise-tasks/logseq/entity/proxy/page/sync see-also:: [[Logseq/Entity/Proxy/Page]], [[Logseq/Entity/Definition]] +task-dependencies:: [[Logseq/Entity/Proxy/Page/mise/Task/docs/serve]] logseq-proxy-url:: logseq://graph/logseq-encode-garden?page=Logseq%2FEntity%2FProxy%2FPage%2Fmise%2FTask%2Fsync -logseq-proxy-codeforge-url:: https://github.com/codekiln/logseq-encode-garden/blob/codex%2F189-proxy-worktree-identity/pages/Logseq___Entity___Proxy___Page___mise___Task___sync.md -logseq-proxy-last-sync-date:: [[2026-10-06]] +logseq-proxy-codeforge-url:: https://github.com/codekiln/logseq-encode-garden/blob/codex%2F202-proxy-task-import-docs/pages/Logseq___Entity___Proxy___Page___mise___Task___sync.md +logseq-proxy-last-sync-date:: [[2026-10-07]] - # Sync a Proxy Page and Its Companion Tasks - Copies a source page into another Logseq garden, together with its entity definitions, declared task references, executable files, helpers, and linked assets. Re-sync refreshes source changes and reports conflicting destination edits before applying changes. - ## Invocation @@ -57,8 +58,15 @@ logseq-proxy-last-sync-date:: [[2026-10-06]] - Local implementation edit: review the destination file against its source and retain or reconcile the edit before syncing again. - Interrupted application: run `mise run logseq:entity:proxy:page:sync --destination /path/to/other-garden --recover` to restore the previous files, then run a fresh preview. - Conflicting ownership: reconcile the source mappings so each destination implementation path has one source owner. + - ## Illustrated guide + - [How Logseq proxies work](../mise-tasks/logseq/entity/proxy/page/docs/index.html) explains first imports, refreshes, multiple source gardens, manifest ownership, Git tracking, and parallel-agent integration. + - Open the guide in a local browser with the imported docs task: + - ~~~sh + mise run logseq:entity:proxy:page:docs:serve + ~~~ + - The server binds to `127.0.0.1`; `--port` selects a port, `--no-open` keeps browser selection manual, and Ctrl-C stops the server. - ## Source and help - - [Sync file task](https://github.com/codekiln/logseq-encode-garden/blob/main/mise-tasks/logseq/entity/proxy/page/sync), [page sync implementation](https://github.com/codekiln/logseq-encode-garden/blob/main/mise-tasks/logseq/entity/proxy/page/lib/core.py), and [companion import implementation](https://github.com/codekiln/logseq-encode-garden/blob/main/mise-tasks/logseq/entity/proxy/page/lib/companions.py). + - [Sync file task](https://github.com/codekiln/logseq-encode-garden/blob/main/mise-tasks/logseq/entity/proxy/page/sync), [page sync implementation](https://github.com/codekiln/logseq-encode-garden/blob/main/mise-tasks/logseq/entity/proxy/page/lib/core.py), and [task import and manifest implementation](https://github.com/codekiln/logseq-encode-garden/blob/main/mise-tasks/logseq/entity/proxy/page/lib/task_imports.py). - ~~~sh mise run logseq:entity:proxy:page:sync --help ~~~