shit_admin: 2026-08-13 12:41:21
This commit is contained in:
@@ -0,0 +1,67 @@
|
||||
---
|
||||
name: symposium-publish
|
||||
description: Publish, update, or withdraw an existing Markdown note through Symposium's host-owned review flow. Use when the user asks to publish, share, update, delete, remove, or withdraw a Symposium page.
|
||||
metadata:
|
||||
copilot-enabled-agents: claude, codex, opencode
|
||||
copilot-builtin-version: "8"
|
||||
---
|
||||
|
||||
# Publish Markdown to Symposium
|
||||
|
||||
Require one existing Markdown source file. When the user asks to delete, remove, or
|
||||
withdraw its current Symposium page, do not generate HTML. Run the host wrapper with
|
||||
only the vault-relative source-note path. Obsidian reads the note's current identity
|
||||
and opens its existing management modal; the user alone chooses Update or Delete.
|
||||
Never tell the user to delete the page at its public URL.
|
||||
|
||||
For publishing or updating, finish a complete, self-contained,
|
||||
passive HTML document before asking Obsidian to review it. Render source-specific
|
||||
content such as Mermaid and Obsidian Bases into static HTML or SVG, embed images,
|
||||
and include no scripts, frames, forms, handlers, redirects, or external assets. Treat
|
||||
YAML frontmatter as note metadata: never render the raw frontmatter block as page
|
||||
content. The exact UTF-8 HTML must not exceed `10485760` bytes.
|
||||
|
||||
Write those final bytes to a new unique `.html` file under
|
||||
`SYMPOSIUM_WORKSPACE_ROOT/.symposium/handoffs/`, creating that
|
||||
directory first when it does not exist. Do not show a prose substitute or ask
|
||||
for confirmation in chat. Instead run the host wrapper with exactly two
|
||||
vault-relative paths: the source note and the staged HTML.
|
||||
|
||||
On macOS or Linux:
|
||||
|
||||
```bash
|
||||
sh "/absolute/path/to/this/skill/directory/symposium-publish.sh" "Notes/source.md" ".symposium/handoffs/unique.html"
|
||||
```
|
||||
|
||||
For withdrawal, omit the staged-HTML argument:
|
||||
|
||||
```bash
|
||||
sh "/absolute/path/to/this/skill/directory/symposium-publish.sh" "Notes/source.md"
|
||||
```
|
||||
|
||||
On Windows, use the `.cmd` wrapper (prefix it with `&` in PowerShell):
|
||||
|
||||
```powershell
|
||||
& "/absolute/path/to/this/skill/directory/symposium-publish.cmd" "Notes/source.md" ".symposium/handoffs/unique.html"
|
||||
```
|
||||
|
||||
Omit the staged-HTML argument on Windows for withdrawal as well.
|
||||
|
||||
With only the source path, the wrapper blocks while Obsidian shows its host-owned
|
||||
Update/Delete management modal. With a staged HTML path, it blocks while Obsidian
|
||||
consumes the artifact and shows its source, title, and a link to a sandboxed
|
||||
local-browser rendering of the exact captured page. Obsidian rejects active or
|
||||
externally loaded content, prevents navigation from the browser preview, removes the
|
||||
original artifact, removes its temporary browser preview after review, and alone reads
|
||||
the current note identity to choose whether confirmation publishes or updates; never
|
||||
choose an action or document id.
|
||||
|
||||
- `cancelled`: stop. No request was sent.
|
||||
- `regenerate`: create a new complete artifact and run the wrapper again. The
|
||||
previous confirmation never applies to regenerated bytes.
|
||||
- `published` or `updated`: return the host-provided public URL verbatim.
|
||||
- `deleted`: report that the host withdrew the page and removed its note identity.
|
||||
- `failed`: if the host says to edit the staged file, address every listed issue in
|
||||
that same file and retry exactly once. Otherwise, or if that retry fails, stop and
|
||||
report the exact host message. Never invent a cause, change unrelated styling, create
|
||||
another filename, bypass the review, or publish directly.
|
||||
@@ -0,0 +1,6 @@
|
||||
@echo off
|
||||
setlocal
|
||||
set "PS=%SystemRoot%\System32\WindowsPowerShell\v1.0\powershell.exe"
|
||||
if not exist "%PS%" set "PS=powershell"
|
||||
"%PS%" -NoProfile -ExecutionPolicy Bypass -File "%~dp0symposium-publish.ps1" %*
|
||||
exit /b %errorlevel%
|
||||
@@ -0,0 +1,44 @@
|
||||
[Console]::OutputEncoding = [System.Text.Encoding]::UTF8
|
||||
$OutputEncoding = [System.Text.Encoding]::UTF8
|
||||
|
||||
$SOURCE = if ($args.Count -ge 1) { $args[0] } else { '' }
|
||||
$STAGED_HTML = if ($args.Count -ge 2) { $args[1] } else { '' }
|
||||
if (($args.Count -ne 1 -and $args.Count -ne 2) -or -not $SOURCE -or ($args.Count -eq 2 -and -not $STAGED_HTML)) {
|
||||
[Console]::Error.WriteLine('Usage: symposium-publish.ps1 <source-note-path> [staged-html-path]')
|
||||
exit 1
|
||||
}
|
||||
|
||||
$OBSIDIAN_CLI = [Environment]::GetEnvironmentVariable('COPILOT_OBSIDIAN_CLI')
|
||||
$WORKSPACE_ROOT = [Environment]::GetEnvironmentVariable('SYMPOSIUM_WORKSPACE_ROOT')
|
||||
if (-not $WORKSPACE_ROOT) {
|
||||
[Console]::Error.WriteLine('The owning Obsidian workspace is unavailable.')
|
||||
exit 1
|
||||
}
|
||||
|
||||
$EXIT_CODE = 0
|
||||
try {
|
||||
if (-not $OBSIDIAN_CLI) { throw 'A compatible Obsidian CLI is unavailable.' }
|
||||
Set-Location -LiteralPath $WORKSPACE_ROOT
|
||||
$VAULT_NAME = Split-Path -Leaf (Get-Location).Path
|
||||
if (-not $VAULT_NAME) { throw 'The owning Obsidian vault is unavailable.' }
|
||||
$SOURCE_B64 = [Convert]::ToBase64String([Text.Encoding]::UTF8.GetBytes($SOURCE))
|
||||
if ($args.Count -eq 1) {
|
||||
$CODE = "(()=>{const decode=(value)=>new TextDecoder().decode(Uint8Array.from(atob(value),(char)=>char.charCodeAt(0)));const bridge=app.plugins.plugins.copilot?.symposiumAgentBridge;if(!bridge)throw new Error('Copilot Symposium host is unavailable.');return bridge.reviewAgentManage(decode('$SOURCE_B64')).then(JSON.stringify);})()"
|
||||
} else {
|
||||
$HTML_B64 = [Convert]::ToBase64String([Text.Encoding]::UTF8.GetBytes($STAGED_HTML))
|
||||
$CODE = "(()=>{const decode=(value)=>new TextDecoder().decode(Uint8Array.from(atob(value),(char)=>char.charCodeAt(0)));const bridge=app.plugins.plugins.copilot?.symposiumAgentBridge;if(!bridge)throw new Error('Copilot Symposium host is unavailable.');return bridge.reviewAgentPublish(decode('$SOURCE_B64'),decode('$HTML_B64')).then(JSON.stringify);})()"
|
||||
}
|
||||
|
||||
$CLI_OUTPUT = & $OBSIDIAN_CLI "vault=$VAULT_NAME" 'eval' "code=$CODE"
|
||||
if ($LASTEXITCODE -ne 0) { throw 'Copilot could not complete the Symposium review.' }
|
||||
$CLI_RESULT = [string](@($CLI_OUTPUT | Where-Object { ([string]$_).StartsWith('=> {') })[-1])
|
||||
if (-not $CLI_RESULT.StartsWith('=> {')) {
|
||||
throw 'Copilot could not complete the Symposium review.'
|
||||
}
|
||||
$OUTCOME = $CLI_RESULT.Substring(3)
|
||||
[Console]::Out.Write($OUTCOME)
|
||||
} catch {
|
||||
[Console]::Error.WriteLine($_.Exception.Message)
|
||||
$EXIT_CODE = 1
|
||||
}
|
||||
exit $EXIT_CODE
|
||||
@@ -0,0 +1,60 @@
|
||||
#!/bin/sh
|
||||
SOURCE=${1:-}
|
||||
STAGED_HTML=${2:-}
|
||||
case "$#" in
|
||||
1) ;;
|
||||
2) ;;
|
||||
*)
|
||||
printf '%s\n' "Usage: sh symposium-publish.sh <source-note-path> [staged-html-path]" >&2
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
[ -n "$SOURCE" ] && { [ "$#" -eq 1 ] || [ -n "$STAGED_HTML" ]; } || {
|
||||
printf '%s\n' "Usage: sh symposium-publish.sh <source-note-path> [staged-html-path]" >&2
|
||||
exit 1
|
||||
}
|
||||
|
||||
OBSIDIAN_CLI=${COPILOT_OBSIDIAN_CLI:-}
|
||||
WORKSPACE_ROOT=${SYMPOSIUM_WORKSPACE_ROOT:-}
|
||||
[ -n "$WORKSPACE_ROOT" ] || {
|
||||
printf '%s\n' "The owning Obsidian workspace is unavailable." >&2
|
||||
exit 1
|
||||
}
|
||||
|
||||
[ -n "$OBSIDIAN_CLI" ] || {
|
||||
printf '%s\n' "A compatible Obsidian CLI is unavailable." >&2
|
||||
exit 1
|
||||
}
|
||||
|
||||
cd "$WORKSPACE_ROOT" || {
|
||||
printf '%s\n' "The owning Obsidian workspace is unavailable." >&2
|
||||
exit 1
|
||||
}
|
||||
VAULT_NAME=${WORKSPACE_ROOT%/}
|
||||
VAULT_NAME=${VAULT_NAME##*/}
|
||||
[ -n "$VAULT_NAME" ] || {
|
||||
printf '%s\n' "The owning Obsidian vault is unavailable." >&2
|
||||
exit 1
|
||||
}
|
||||
|
||||
SOURCE_B64=$(printf '%s' "$SOURCE" | base64 | tr -d '\r\n')
|
||||
if [ "$#" -eq 1 ]; then
|
||||
CODE="(()=>{const decode=(value)=>new TextDecoder().decode(Uint8Array.from(atob(value),(char)=>char.charCodeAt(0)));const bridge=app.plugins.plugins.copilot?.symposiumAgentBridge;if(!bridge)throw new Error('Copilot Symposium host is unavailable.');return bridge.reviewAgentManage(decode('$SOURCE_B64')).then(JSON.stringify);})()"
|
||||
else
|
||||
HTML_B64=$(printf '%s' "$STAGED_HTML" | base64 | tr -d '\r\n')
|
||||
CODE="(()=>{const decode=(value)=>new TextDecoder().decode(Uint8Array.from(atob(value),(char)=>char.charCodeAt(0)));const bridge=app.plugins.plugins.copilot?.symposiumAgentBridge;if(!bridge)throw new Error('Copilot Symposium host is unavailable.');return bridge.reviewAgentPublish(decode('$SOURCE_B64'),decode('$HTML_B64')).then(JSON.stringify);})()"
|
||||
fi
|
||||
|
||||
CLI_OUTPUT=$("$OBSIDIAN_CLI" "vault=$VAULT_NAME" eval "code=$CODE") || exit $?
|
||||
CLI_RESULT=$(printf '%s\n' "$CLI_OUTPUT" | sed -n '/^=> {/p' | sed -n '$p')
|
||||
case "$CLI_RESULT" in
|
||||
"=> {"*)
|
||||
OUTCOME=${CLI_RESULT#"=> "}
|
||||
printf '%s\n' "$OUTCOME"
|
||||
exit 0
|
||||
;;
|
||||
*)
|
||||
printf '%s\n' "Copilot could not complete the Symposium review." >&2
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
Reference in New Issue
Block a user