create-egregore 0.21.1 → 0.21.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/assets/egregore-launcher.js +2 -2
- package/lib/renderer-install.js +42 -0
- package/lib/setup.js +15 -14
- package/package.json +2 -2
- package/runtime/claude/.claude/context/telemetry.md +27 -48
- package/runtime/claude/.claude/skills/issue/SKILL.md +13 -0
- package/runtime/claude/.claude/skills/view/SKILL.md +2 -1
- package/runtime/claude/bin/artifact-renderer-install.sh +157 -0
- package/runtime/claude/bin/artifact-renderer.sh +57 -0
- package/runtime/claude/bin/handoff-preview.sh +2 -4
- package/runtime/claude/bin/handoff-run.sh +4 -11
- package/runtime/claude/bin/lib/artifact-renderer/dependencies-lock.json +94 -0
- package/runtime/claude/bin/lib/artifact-renderer/dependencies.json +8 -0
- package/runtime/claude/bin/lib/dashboard-artifact.sh +2 -2
- package/runtime/claude/bin/lib/greeting.sh +2 -13
- package/runtime/claude/bin/post-update.sh +5 -0
- package/runtime/claude/bin/publish-artifact.sh +6 -27
- package/runtime/claude/bin/view-render.sh +2 -13
- package/runtime/claude/egregore_runtime/issue_reporting.py +38 -7
- package/runtime/claude/egregore_runtime/upgrade.py +51 -0
- package/runtime/claude/manifest.json +4 -0
- package/runtime/codex/bin/artifact-renderer-install.sh +157 -0
- package/runtime/codex/bin/artifact-renderer.sh +57 -0
- package/runtime/codex/bin/handoff-preview.sh +2 -4
- package/runtime/codex/bin/handoff-run.sh +4 -11
- package/runtime/codex/bin/lib/artifact-renderer/dependencies-lock.json +94 -0
- package/runtime/codex/bin/lib/artifact-renderer/dependencies.json +8 -0
- package/runtime/codex/bin/lib/dashboard-artifact.sh +2 -2
- package/runtime/codex/bin/lib/greeting.sh +2 -13
- package/runtime/codex/bin/post-update.sh +5 -0
- package/runtime/codex/bin/publish-artifact.sh +6 -27
- package/runtime/codex/bin/view-render.sh +2 -13
- package/runtime/codex/egregore_runtime/issue_reporting.py +38 -7
- package/runtime/codex/egregore_runtime/upgrade.py +51 -0
- package/runtime/codex/manifest.json +4 -0
- package/runtime/pi/bin/artifact-renderer-install.sh +157 -0
- package/runtime/pi/bin/artifact-renderer.sh +57 -0
- package/runtime/pi/bin/handoff-preview.sh +2 -4
- package/runtime/pi/bin/handoff-run.sh +4 -11
- package/runtime/pi/bin/lib/artifact-renderer/dependencies-lock.json +94 -0
- package/runtime/pi/bin/lib/artifact-renderer/dependencies.json +8 -0
- package/runtime/pi/bin/lib/dashboard-artifact.sh +2 -2
- package/runtime/pi/bin/lib/greeting.sh +2 -13
- package/runtime/pi/bin/pi-product-workflows.mjs +1 -4
- package/runtime/pi/bin/post-update.sh +5 -0
- package/runtime/pi/bin/publish-artifact.sh +6 -27
- package/runtime/pi/bin/view-render.sh +2 -13
- package/runtime/pi/egregore_runtime/issue_reporting.py +38 -7
- package/runtime/pi/egregore_runtime/upgrade.py +51 -0
- package/runtime/pi/manifest.json +4 -0
- package/runtime/prime/bin/artifact-renderer-install.sh +157 -0
- package/runtime/prime/bin/artifact-renderer.sh +57 -0
- package/runtime/prime/bin/handoff-preview.sh +2 -4
- package/runtime/prime/bin/handoff-run.sh +4 -11
- package/runtime/prime/bin/lib/artifact-renderer/dependencies-lock.json +94 -0
- package/runtime/prime/bin/lib/artifact-renderer/dependencies.json +8 -0
- package/runtime/prime/bin/lib/dashboard-artifact.sh +2 -2
- package/runtime/prime/bin/lib/greeting.sh +2 -13
- package/runtime/prime/bin/pi-product-workflows.mjs +1 -4
- package/runtime/prime/bin/post-update.sh +5 -0
- package/runtime/prime/bin/publish-artifact.sh +6 -27
- package/runtime/prime/bin/view-render.sh +2 -13
- package/runtime/prime/egregore_runtime/issue_reporting.py +38 -7
- package/runtime/prime/egregore_runtime/upgrade.py +51 -0
- package/runtime/prime/manifest.json +4 -0
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
// egregore-launcher-version: 0.21.
|
|
2
|
+
// egregore-launcher-version: 0.21.3
|
|
3
3
|
//
|
|
4
4
|
// egregore — launch and browse Egregore instances from your terminal.
|
|
5
5
|
// Installed by create-egregore. Reads ~/.egregore/instances.json.
|
|
@@ -35,7 +35,7 @@ const crypto = require("node:crypto");
|
|
|
35
35
|
const { spawnSync, spawn } = require("node:child_process");
|
|
36
36
|
const readline = require("node:readline");
|
|
37
37
|
|
|
38
|
-
const VERSION = "0.21.
|
|
38
|
+
const VERSION = "0.21.3";
|
|
39
39
|
const REGISTRY = path.join(os.homedir(), ".egregore", "instances.json");
|
|
40
40
|
const DEFAULT_FILE = path.join(os.homedir(), ".egregore", "default");
|
|
41
41
|
const UPDATE_CACHE_FILE = path.join(os.homedir(), ".egregore", "update-check.json");
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
const { spawn } = require("node:child_process");
|
|
4
|
+
const path = require("node:path");
|
|
5
|
+
|
|
6
|
+
// An installer starts npm children. Kill the whole group on timeout so retries
|
|
7
|
+
// cannot race a download left behind by a terminated setup process.
|
|
8
|
+
function runRendererInstaller(root, { timeoutMs = 180000, killGraceMs = 1000 } = {}) {
|
|
9
|
+
return new Promise((resolve) => {
|
|
10
|
+
const grouped = process.platform !== "win32";
|
|
11
|
+
const child = spawn("bash", [path.join(root, "bin", "artifact-renderer-install.sh")], {
|
|
12
|
+
cwd: root, detached: grouped, stdio: ["ignore", "pipe", "pipe"],
|
|
13
|
+
});
|
|
14
|
+
let stdout = "", stderr = "", error;
|
|
15
|
+
let forceTimer;
|
|
16
|
+
const stop = (signal) => {
|
|
17
|
+
try {
|
|
18
|
+
if (grouped && child.pid) process.kill(-child.pid, signal);
|
|
19
|
+
else child.kill(signal);
|
|
20
|
+
} catch (err) {
|
|
21
|
+
if (err.code !== "ESRCH") error = err;
|
|
22
|
+
}
|
|
23
|
+
};
|
|
24
|
+
child.stdout.on("data", (data) => { stdout += data; });
|
|
25
|
+
child.stderr.on("data", (data) => { stderr += data; });
|
|
26
|
+
child.once("error", (err) => { error = err; });
|
|
27
|
+
const timer = setTimeout(() => {
|
|
28
|
+
error = new Error("Artifact renderer installation timed out");
|
|
29
|
+
stop("SIGTERM");
|
|
30
|
+
forceTimer = setTimeout(() => stop("SIGKILL"), killGraceMs);
|
|
31
|
+
}, timeoutMs);
|
|
32
|
+
child.once("close", (status) => {
|
|
33
|
+
clearTimeout(timer);
|
|
34
|
+
clearTimeout(forceTimer);
|
|
35
|
+
// A descendant may have detached its output pipes before Bash exited.
|
|
36
|
+
if (error && grouped) stop("SIGKILL");
|
|
37
|
+
resolve({ status, stdout, stderr, error });
|
|
38
|
+
});
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
module.exports = { runRendererInstaller };
|
package/lib/setup.js
CHANGED
|
@@ -7,6 +7,7 @@ const { execSync, execFileSync, spawnSync, spawn } = require("node:child_process
|
|
|
7
7
|
const fs = require("node:fs");
|
|
8
8
|
const path = require("node:path");
|
|
9
9
|
const os = require("node:os");
|
|
10
|
+
const { runRendererInstaller } = require("./renderer-install");
|
|
10
11
|
const {
|
|
11
12
|
hasCodexRuntimeSupport,
|
|
12
13
|
installCodexRuntime,
|
|
@@ -111,6 +112,20 @@ async function finalizeRuntimeSetup(egregoreDir, ui, {
|
|
|
111
112
|
|
|
112
113
|
if (afterRuntimeInstall) await afterRuntimeInstall(runtimeSummary, preferredRuntime);
|
|
113
114
|
|
|
115
|
+
// Provision the pinned renderer during explicit installation, not at first
|
|
116
|
+
// preview or session launch. All harnesses share this managed local install.
|
|
117
|
+
const rendererInstaller = path.join(egregoreDir, "bin", "artifact-renderer-install.sh");
|
|
118
|
+
if (!fs.existsSync(rendererInstaller)) {
|
|
119
|
+
throw new Error("Artifact renderer setup is unavailable in this Runtime; update create-egregore and retry.");
|
|
120
|
+
}
|
|
121
|
+
ui.info("Preparing artifact renderer…");
|
|
122
|
+
const renderer = await runRendererInstaller(egregoreDir);
|
|
123
|
+
if (renderer.error || renderer.status !== 0) {
|
|
124
|
+
const detail = String(renderer.stderr || renderer.error?.message || `installer exited ${renderer.status}`).trim();
|
|
125
|
+
throw new Error(`Artifact renderer setup did not complete. ${detail}\nFrom this Egregore, run bash bin/artifact-renderer-install.sh, then retry setup.`);
|
|
126
|
+
}
|
|
127
|
+
ui.success("Artifact renderer ready");
|
|
128
|
+
|
|
114
129
|
// Connect is an authenticated additive overlay on the exact OSS runtime.
|
|
115
130
|
// Local instances return immediately; network failure never breaks setup.
|
|
116
131
|
try {
|
|
@@ -725,20 +740,6 @@ async function install(data, ui, targetDir, opts = {}) {
|
|
|
725
740
|
}
|
|
726
741
|
}
|
|
727
742
|
|
|
728
|
-
// Warm the npx cache for egregore-artifacts so the first /view or
|
|
729
|
-
// publish-artifact call doesn't pay a cold npm download (~5-10s).
|
|
730
|
-
// Background + detached — we don't care about completion, and any
|
|
731
|
-
// failure is silent. The first real use benefits if this finishes in
|
|
732
|
-
// time, otherwise it costs nothing.
|
|
733
|
-
try {
|
|
734
|
-
const { spawn } = require("child_process");
|
|
735
|
-
const warm = spawn("npx", ["-y", "egregore-artifacts@latest", "--help"], {
|
|
736
|
-
detached: true,
|
|
737
|
-
stdio: "ignore",
|
|
738
|
-
});
|
|
739
|
-
warm.unref();
|
|
740
|
-
} catch { /* ignore — cosmetic warmup */ }
|
|
741
|
-
|
|
742
743
|
// Done — full-screen summary bookend if we can; inline workspace list
|
|
743
744
|
// otherwise. Same contract as localFounderFlow.
|
|
744
745
|
const workspaces = [
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "create-egregore",
|
|
3
|
-
"version": "0.21.
|
|
3
|
+
"version": "0.21.3",
|
|
4
4
|
"description": "Set up Egregore for your team in one command \u2014 installs the egregore launcher and your choice of Claude Code, Codex, or Pi.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"bin": {
|
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
"test:e2e": "node --test test/e2e-local.test.js",
|
|
20
20
|
"test:all": "npm run test:runtime && node --test test/",
|
|
21
21
|
"test:runtime": "node ../../bin/capability-distribution.mjs validate --root ../.. && node scripts/build-runtime-bundle.mjs --check && node scripts/build-claude-runtime-bundle.mjs --check && node scripts/build-pi-runtime-bundle.mjs --check && node scripts/build-prime-runtime-bundle.mjs --check && node ../../bin/prime-render-spec.mjs --check && node ../../bin/pi-render-spec.mjs --check && node ../../api/scripts/build-connect-runtime-pack.mjs --check && bash ../../bin/tests/test-codex-native-skills.sh && bash ../../bin/tests/test-codex-spec-render.sh && node ../../bin/capability-distribution.mjs skill-contract --root ../.. --strict-contract && bash ../../bin/tests/test-bundle-skill-scripts.sh && node --test test/bundle-skill-scripts.test.js",
|
|
22
|
-
"test:package": "node --test --test-concurrency=1 test/invite-install.test.js test/capability-distribution.test.js test/connect-runtime.test.js test/context.test.js test/path-lookup.test.js test/nixos-portability.test.js test/parse-join-target.test.js test/skip-repos.test.js test/install-origin-guard.test.js test/onboarding-shortcircuit.test.js test/runtime-identity.test.js test/welcome-screen.test.js test/runtime-selection.test.js test/command-generation.test.js test/auth-gh.test.js test/gauntlet-fixes.test.js test/claude-runtime.test.js test/codex-runtime.test.js test/pi-runtime.test.js test/prime-runtime.test.js test/prime-branch-policy.test.js test/prime-bridge-skill.test.js test/pi-observe-context.test.js test/native-command-observe.test.js test/prime-rpc-driver.test.js test/pi-session-smoke.test.js test/prime-session-smoke.test.js test/pi-product-workflows.test.js test/installer-runtime-source.test.js test/runtime-ownership.test.js test/installer-finalization.test.js test/runtime-readiness.test.js test/scroll-repro.test.js test/launcher-refocus-redraw.test.js test/multiselect-remote-search.test.js test/back-navigation.test.js test/manifest-form.test.js test/launcher-delete.test.js test/launcher-connect.test.js test/installer-connect-choice.test.js test/launcher-connected-status.test.js test/launcher-telemetry.test.js test/launcher-runtime.test.js test/launcher-settings.test.js test/launcher-runtime-candidate.test.js test/launcher-permissions.test.js test/launcher-update.test.js test/harness-add.test.js test/connected-config.test.js test/workflow-settings.test.js"
|
|
22
|
+
"test:package": "node --test --test-concurrency=1 test/invite-install.test.js test/capability-distribution.test.js test/connect-runtime.test.js test/context.test.js test/path-lookup.test.js test/nixos-portability.test.js test/parse-join-target.test.js test/skip-repos.test.js test/install-origin-guard.test.js test/onboarding-shortcircuit.test.js test/runtime-identity.test.js test/welcome-screen.test.js test/runtime-selection.test.js test/command-generation.test.js test/auth-gh.test.js test/gauntlet-fixes.test.js test/claude-runtime.test.js test/codex-runtime.test.js test/pi-runtime.test.js test/prime-runtime.test.js test/prime-branch-policy.test.js test/prime-bridge-skill.test.js test/pi-observe-context.test.js test/native-command-observe.test.js test/prime-rpc-driver.test.js test/pi-session-smoke.test.js test/prime-session-smoke.test.js test/pi-product-workflows.test.js test/installer-runtime-source.test.js test/runtime-ownership.test.js test/installer-finalization.test.js test/renderer-install.test.js test/runtime-readiness.test.js test/scroll-repro.test.js test/launcher-refocus-redraw.test.js test/multiselect-remote-search.test.js test/back-navigation.test.js test/manifest-form.test.js test/launcher-delete.test.js test/launcher-connect.test.js test/installer-connect-choice.test.js test/launcher-connected-status.test.js test/launcher-telemetry.test.js test/launcher-runtime.test.js test/launcher-settings.test.js test/launcher-runtime-candidate.test.js test/launcher-permissions.test.js test/launcher-update.test.js test/harness-add.test.js test/connected-config.test.js test/workflow-settings.test.js"
|
|
23
23
|
},
|
|
24
24
|
"files": [
|
|
25
25
|
"bin/",
|
|
@@ -153,51 +153,30 @@ On the first session where telemetry events are emitted, if `telemetry_noticed`
|
|
|
153
153
|
|
|
154
154
|
Then set `telemetry_noticed: true` in the state file. Never repeat this notice.
|
|
155
155
|
|
|
156
|
-
##
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
-
|
|
183
|
-
- Conversation transcript or user prompts
|
|
184
|
-
- Environment variables or secrets
|
|
185
|
-
- Org-specific data (sanitized before sending — org names, person names, tokens replaced)
|
|
186
|
-
|
|
187
|
-
### Opt-out
|
|
188
|
-
|
|
189
|
-
- `EGREGORE_NO_REPORTS=1` in `.env`
|
|
190
|
-
- `.egregore-state.json` → `"session_reports": false`
|
|
191
|
-
- Simply answer "No thanks" when prompted during `/wrap`
|
|
192
|
-
- `DO_NOT_TRACK=1` also disables reports
|
|
193
|
-
|
|
194
|
-
### Transport
|
|
195
|
-
|
|
196
|
-
- Direct to Supabase via anon key (INSERT-only RLS policy)
|
|
197
|
-
- If network fails: saved locally to `~/.egregore/reports/` as fallback
|
|
198
|
-
- Telegram notification to maintainers fires server-side via Supabase DB webhook
|
|
199
|
-
- Optional: GitHub issue creation on `egregore-labs/egregore` (user chooses each time)
|
|
200
|
-
|
|
201
|
-
### Configuration
|
|
202
|
-
|
|
203
|
-
Reports require `report_url` and `report_key` in `egregore.json`. New OSS installations get these automatically via `create-egregore`. If missing, the report prompt is skipped entirely.
|
|
156
|
+
## Framework support and legacy session feedback
|
|
157
|
+
|
|
158
|
+
For an Egregore bug, including the historical `/issue egregore:` wording, use
|
|
159
|
+
the [issue workflow](../skills/issue/SKILL.md). Connected instances prepare an
|
|
160
|
+
exact private support preview and submit only after confirmation. Local users
|
|
161
|
+
can explicitly choose a public upstream report. An internal issue stays within
|
|
162
|
+
its organization's memory or configured tracker; it does not automatically
|
|
163
|
+
reach Egregore support. `/wrap` does not collect or submit session feedback.
|
|
164
|
+
|
|
165
|
+
The older `bin/session-report.sh` is a feedback-storage compatibility helper,
|
|
166
|
+
not a support-reporting route. It inserts selected feedback into `session_reports`
|
|
167
|
+
when `report_url` and `report_key` are configured. A `submitted` receipt means
|
|
168
|
+
only that storage accepted the feedback: no GitHub issue was created and no
|
|
169
|
+
Telegram message was sent. The authenticated database callback acknowledges
|
|
170
|
+
storage without planning or dispatching a notification to a named teammate.
|
|
171
|
+
Transport failure saves feedback locally under `~/.egregore/reports/`; that
|
|
172
|
+
does not establish remote storage or delivery. Missing configuration skips
|
|
173
|
+
submission.
|
|
174
|
+
|
|
175
|
+
Never invoke legacy feedback automatically, generate it from a transcript, or
|
|
176
|
+
use it as a fallback when private support fails. Only explicitly selected and
|
|
177
|
+
reviewed content may be shared. The helper adds legacy user and organization
|
|
178
|
+
labels; it does not guarantee anonymization or scrub arbitrary input.
|
|
179
|
+
|
|
180
|
+
Legacy feedback can be disabled with `EGREGORE_NO_REPORTS=1` or
|
|
181
|
+
`DO_NOT_TRACK=1` in the process environment, or `"session_reports": false` in
|
|
182
|
+
`.egregore-state.json`. These switches do not grant consent to submit content.
|
|
@@ -67,6 +67,12 @@ its default recipient is **Egregore support, private**. Local/OSS users may
|
|
|
67
67
|
explicitly choose `upstream` for a **public** report. Connected users can also
|
|
68
68
|
choose public upstream explicitly. Never fall back from private to public.
|
|
69
69
|
|
|
70
|
+
Treat the historical `egregore:` prefix as framework-support intent and use
|
|
71
|
+
this reviewed reporting flow. Never route a framework bug through the
|
|
72
|
+
legacy session-feedback helper: it only stores feedback and does not
|
|
73
|
+
file a support issue or send a Telegram notification. Being Connected does not
|
|
74
|
+
turn an internal issue in the customer's memory into a report to Egregore.
|
|
75
|
+
|
|
70
76
|
Use `'{title}'` for the concise title derived from the user's report and
|
|
71
77
|
`'{report}'` for the report text the user supplied or reviewed.
|
|
72
78
|
Write an embedded single quote as `'\''` in each substituted value.
|
|
@@ -119,6 +125,13 @@ review the private issue in its Project/Archive. Keep a failed/uncertain report'
|
|
|
119
125
|
request ID; no backend failure authorizes public publication or a fresh blind
|
|
120
126
|
submission.
|
|
121
127
|
|
|
128
|
+
Report the confirmed outcome precisely: a preview is not submitted; a local
|
|
129
|
+
issue is saved within this organization; only a matching private receipt with
|
|
130
|
+
`submission_state: filed` means filed with Egregore support. Other states need
|
|
131
|
+
recovery using the same request ID. A filed issue does not prove Telegram
|
|
132
|
+
delivery: `notification_state: unverified` must never be described as sent or
|
|
133
|
+
received. Only a separate delivery receipt can establish that.
|
|
134
|
+
|
|
122
135
|
Public reports use the reporter's GitHub authentication and return a public
|
|
123
136
|
issue URL. Destination comes only from HTTPS GitHub `upstream_url`; absent means
|
|
124
137
|
`egregore-labs/egregore`, `none` means no upstream. Do not infer it from remotes.
|
|
@@ -151,7 +151,8 @@ authorized result path; everything else is `document`.
|
|
|
151
151
|
|
|
152
152
|
**On the script route, `bin/view-render.sh` owns everything in this section**:
|
|
153
153
|
it resolves the packaged renderer locally (checked-out
|
|
154
|
-
`packages/egregore-artifacts` first, then the
|
|
154
|
+
`packages/egregore-artifacts` with dependencies first, then the instance's
|
|
155
|
+
managed renderer, then an installed `egregore-artifacts` on PATH;
|
|
155
156
|
never `npx`, never a registry fetch), stages complete `memory/...` documents
|
|
156
157
|
through the existing authorized `Runtime.open_source` adapter (ordinary model
|
|
157
158
|
evidence reads remain bounded), serves unchanged content from the content-addressed
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# Explicit setup/update/repair only. Rendering and startup must never install.
|
|
3
|
+
set -euo pipefail
|
|
4
|
+
|
|
5
|
+
SCRIPT_DIR="$(cd "$(dirname "$0")/.." && pwd)"
|
|
6
|
+
TARGET_ROOT="$SCRIPT_DIR"
|
|
7
|
+
CHECK_ONLY=0
|
|
8
|
+
LOCK_FD=""
|
|
9
|
+
while [ "$#" -gt 0 ]; do
|
|
10
|
+
case "$1" in
|
|
11
|
+
--root)
|
|
12
|
+
[ "$#" -ge 2 ] && [ -n "$2" ] || { echo 'artifact renderer: --root needs a directory' >&2; exit 2; }
|
|
13
|
+
TARGET_ROOT="$2"; shift 2 ;;
|
|
14
|
+
--check) CHECK_ONLY=1; shift ;;
|
|
15
|
+
--lock-fd) LOCK_FD="${2:?missing lock descriptor}"; shift 2 ;;
|
|
16
|
+
*) echo 'Usage: bash bin/artifact-renderer-install.sh [--root <instance>] [--check]' >&2; exit 2 ;;
|
|
17
|
+
esac
|
|
18
|
+
done
|
|
19
|
+
# npm 11 treats a symlinked --prefix as a linked root package, which makes
|
|
20
|
+
# `ci` reject the lockfile (including macOS's /var -> /private/var alias).
|
|
21
|
+
TARGET_ROOT="$(cd "$TARGET_ROOT" && pwd -P)"
|
|
22
|
+
MANIFEST_DIR="$SCRIPT_DIR/bin/lib/artifact-renderer"
|
|
23
|
+
|
|
24
|
+
for required in dependencies.json dependencies-lock.json; do
|
|
25
|
+
[ -f "$MANIFEST_DIR/$required" ] || {
|
|
26
|
+
echo "artifact renderer: pinned $required is missing; update the framework and retry" >&2
|
|
27
|
+
exit 1
|
|
28
|
+
}
|
|
29
|
+
done
|
|
30
|
+
NODE_BIN="$(bash "$SCRIPT_DIR/bin/node-run.sh" -p 'process.execPath')"
|
|
31
|
+
export PATH="$(dirname "$NODE_BIN"):$PATH"
|
|
32
|
+
MANIFEST_INFO="$(python3 - "$MANIFEST_DIR" <<'PY'
|
|
33
|
+
import hashlib, json, pathlib, re, sys
|
|
34
|
+
source = pathlib.Path(sys.argv[1])
|
|
35
|
+
version = json.loads((source / 'dependencies.json').read_text())['dependencies']['egregore-artifacts']
|
|
36
|
+
if not isinstance(version, str) or not re.fullmatch(r'[0-9]+\.[0-9]+\.[0-9]+(?:-[0-9A-Za-z.-]+)?', version):
|
|
37
|
+
raise SystemExit('artifact renderer: an exact package version is required')
|
|
38
|
+
digest = hashlib.sha256((source / 'dependencies-lock.json').read_bytes()).hexdigest()[:16]
|
|
39
|
+
print(version, version + '-' + digest)
|
|
40
|
+
PY
|
|
41
|
+
)"
|
|
42
|
+
read -r VERSION INSTALL_ID <<< "$MANIFEST_INFO"
|
|
43
|
+
TOOLS_DIR="$TARGET_ROOT/.egregore/tools/artifact-renderer"
|
|
44
|
+
PREFIX="$TOOLS_DIR/$INSTALL_ID"
|
|
45
|
+
|
|
46
|
+
renderer_ready() {
|
|
47
|
+
local candidate="$1"
|
|
48
|
+
cmp -s "$MANIFEST_DIR/dependencies.json" "$candidate/package.json" || return 1
|
|
49
|
+
cmp -s "$MANIFEST_DIR/dependencies-lock.json" "$candidate/package-lock.json" || return 1
|
|
50
|
+
"$NODE_BIN" -e '
|
|
51
|
+
const fs = require("node:fs");
|
|
52
|
+
const path = require("node:path");
|
|
53
|
+
const actual = JSON.parse(fs.readFileSync(path.join(process.argv[1], "node_modules/egregore-artifacts/package.json"), "utf8"));
|
|
54
|
+
if (actual.version !== process.argv[2]) process.exit(1);
|
|
55
|
+
' "$candidate" "$VERSION" >/dev/null 2>&1 || return 1
|
|
56
|
+
"$NODE_BIN" "$candidate/node_modules/egregore-artifacts/bin/cli.js" --help >/dev/null 2>&1
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
if renderer_ready "$PREFIX"; then
|
|
60
|
+
printf 'Artifact renderer %s is ready\n' "$VERSION"
|
|
61
|
+
exit 0
|
|
62
|
+
fi
|
|
63
|
+
if [ "$CHECK_ONLY" = 1 ]; then
|
|
64
|
+
printf 'Artifact renderer %s is not ready; run bash bin/artifact-renderer-install.sh\n' "$VERSION" >&2
|
|
65
|
+
exit 1
|
|
66
|
+
fi
|
|
67
|
+
|
|
68
|
+
NPM_BIN="$(command -v npm || true)"
|
|
69
|
+
[ -n "$NPM_BIN" ] && "$NPM_BIN" --version >/dev/null 2>&1 || {
|
|
70
|
+
echo 'artifact renderer: npm is unavailable; install Node with npm, then retry' >&2
|
|
71
|
+
exit 1
|
|
72
|
+
}
|
|
73
|
+
mkdir -p "$TOOLS_DIR"
|
|
74
|
+
[ ! -L "$PREFIX" ] || { echo 'artifact renderer: managed install must not be a symbolic link' >&2; exit 1; }
|
|
75
|
+
LOCK="$TOOLS_DIR/.$INSTALL_ID.lock"
|
|
76
|
+
# A kernel lock survives in children while they are still installing and is
|
|
77
|
+
# released after forced interruption. Its persistent file never means "busy".
|
|
78
|
+
# Re-exec under the inherited descriptor so Bash, npm, and cleanup all share
|
|
79
|
+
# ownership; unlike mkdir locks, a killed process cannot leave a stale owner.
|
|
80
|
+
if [ -z "$LOCK_FD" ]; then
|
|
81
|
+
exec python3 - "$LOCK" "$SCRIPT_DIR/bin/artifact-renderer-install.sh" "$TARGET_ROOT" <<'PY'
|
|
82
|
+
import fcntl, os, stat, sys
|
|
83
|
+
lock, script, root = sys.argv[1:]
|
|
84
|
+
fd = os.open(lock, os.O_CREAT | os.O_RDWR | getattr(os, 'O_NOFOLLOW', 0), 0o600)
|
|
85
|
+
if not stat.S_ISREG(os.fstat(fd).st_mode):
|
|
86
|
+
raise SystemExit('artifact renderer: invalid install lock')
|
|
87
|
+
try:
|
|
88
|
+
fcntl.flock(fd, fcntl.LOCK_EX | fcntl.LOCK_NB)
|
|
89
|
+
except BlockingIOError:
|
|
90
|
+
raise SystemExit('artifact renderer: another install is in progress; retry after it finishes')
|
|
91
|
+
os.set_inheritable(fd, True)
|
|
92
|
+
os.execvp('bash', ['bash', script, '--root', root, '--lock-fd', str(fd)])
|
|
93
|
+
PY
|
|
94
|
+
fi
|
|
95
|
+
# Validate the internal descriptor instead of accepting an unlocked re-entry.
|
|
96
|
+
python3 - "$LOCK_FD" "$LOCK" <<'PY'
|
|
97
|
+
import fcntl, os, sys
|
|
98
|
+
try:
|
|
99
|
+
fd = int(sys.argv[1])
|
|
100
|
+
if not os.path.samestat(os.fstat(fd), os.stat(sys.argv[2])):
|
|
101
|
+
raise ValueError('wrong lock file')
|
|
102
|
+
fcntl.flock(fd, fcntl.LOCK_EX | fcntl.LOCK_NB)
|
|
103
|
+
except (ValueError, OSError):
|
|
104
|
+
raise SystemExit('artifact renderer: install lock is unavailable')
|
|
105
|
+
PY
|
|
106
|
+
STAGE=""
|
|
107
|
+
BACKUP="$TOOLS_DIR/.$INSTALL_ID.previous"
|
|
108
|
+
cleanup() {
|
|
109
|
+
if [ -n "$BACKUP" ] && [ -d "$BACKUP" ] && [ ! -e "$PREFIX" ]; then mv "$BACKUP" "$PREFIX"; fi
|
|
110
|
+
[ -z "$STAGE" ] || rm -rf "$STAGE"
|
|
111
|
+
}
|
|
112
|
+
trap cleanup EXIT
|
|
113
|
+
trap 'exit 130' INT
|
|
114
|
+
trap 'exit 143' TERM
|
|
115
|
+
|
|
116
|
+
# Recover an interrupted swap and discard only this pin's abandoned staging
|
|
117
|
+
# trees. Another Runtime's version/lock and in-progress install stay untouched.
|
|
118
|
+
if [ -d "$BACKUP" ]; then
|
|
119
|
+
if [ ! -e "$PREFIX" ]; then mv "$BACKUP" "$PREFIX"; else rm -rf "$BACKUP"; fi
|
|
120
|
+
fi
|
|
121
|
+
for abandoned in "$TOOLS_DIR/.$INSTALL_ID.stage."*; do
|
|
122
|
+
[ ! -d "$abandoned" ] || rm -rf "$abandoned"
|
|
123
|
+
done
|
|
124
|
+
|
|
125
|
+
# Recheck under the lock in case another explicit installer just completed.
|
|
126
|
+
if renderer_ready "$PREFIX"; then
|
|
127
|
+
printf 'Artifact renderer %s is ready\n' "$VERSION"
|
|
128
|
+
exit 0
|
|
129
|
+
fi
|
|
130
|
+
STAGE="$(mktemp -d "$TOOLS_DIR/.$INSTALL_ID.stage.XXXXXX")"
|
|
131
|
+
cp "$MANIFEST_DIR/dependencies.json" "$STAGE/package.json"
|
|
132
|
+
cp "$MANIFEST_DIR/dependencies-lock.json" "$STAGE/package-lock.json"
|
|
133
|
+
printf 'Installing artifact renderer %s with locked dependencies…\n' "$VERSION"
|
|
134
|
+
if ! "$NPM_BIN" ci --prefix "$STAGE" --ignore-scripts --omit=dev --no-audit --no-fund >"$STAGE/install.log" 2>&1; then
|
|
135
|
+
echo 'artifact renderer: installation failed; the previous install was kept' >&2
|
|
136
|
+
# npm often appends a long usage guide after the actionable error.
|
|
137
|
+
head -12 "$STAGE/install.log" >&2
|
|
138
|
+
if [ "$(wc -l < "$STAGE/install.log")" -gt 20 ]; then
|
|
139
|
+
echo '… npm output abbreviated …' >&2
|
|
140
|
+
tail -8 "$STAGE/install.log" >&2
|
|
141
|
+
fi
|
|
142
|
+
exit 1
|
|
143
|
+
fi
|
|
144
|
+
if ! renderer_ready "$STAGE"; then
|
|
145
|
+
echo 'artifact renderer: the installed package failed its readiness check; the previous install was kept' >&2
|
|
146
|
+
exit 1
|
|
147
|
+
fi
|
|
148
|
+
rm -f "$STAGE/install.log"
|
|
149
|
+
# Both renames are on the same filesystem. No live install is removed until
|
|
150
|
+
# the complete replacement has passed its version/dependency probe.
|
|
151
|
+
if [ -e "$PREFIX" ]; then
|
|
152
|
+
mv "$PREFIX" "$BACKUP"
|
|
153
|
+
fi
|
|
154
|
+
mv "$STAGE" "$PREFIX"
|
|
155
|
+
STAGE=""
|
|
156
|
+
[ ! -d "$BACKUP" ] || rm -rf "$BACKUP"
|
|
157
|
+
printf 'Artifact renderer %s installed\n' "$VERSION"
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
set -euo pipefail
|
|
3
|
+
|
|
4
|
+
# One offline resolver for source checkouts and installed Egregore instances.
|
|
5
|
+
# Provisioning is explicit (setup/update/artifact-renderer-install.sh), never
|
|
6
|
+
# a side effect of rendering private content.
|
|
7
|
+
ROOT="$(cd "$(dirname "$0")/.." && pwd)"
|
|
8
|
+
|
|
9
|
+
resolve_renderer() {
|
|
10
|
+
local source_cli="$ROOT/packages/egregore-artifacts/bin/cli.js"
|
|
11
|
+
local manifest_dir="$ROOT/bin/lib/artifact-renderer"
|
|
12
|
+
local managed="" install_id=""
|
|
13
|
+
local installed=""
|
|
14
|
+
|
|
15
|
+
if [ "${EGREGORE_USE_PUBLISHED:-0}" != "1" ] && \
|
|
16
|
+
[ -f "$source_cli" ] && \
|
|
17
|
+
[ -d "$ROOT/packages/egregore-artifacts/node_modules/react" ]; then
|
|
18
|
+
printf '%s\n' "$source_cli"
|
|
19
|
+
return 0
|
|
20
|
+
fi
|
|
21
|
+
if [ -f "$manifest_dir/dependencies.json" ] && [ -f "$manifest_dir/dependencies-lock.json" ]; then
|
|
22
|
+
install_id="$(python3 - "$manifest_dir" <<'PY'
|
|
23
|
+
import hashlib, json, pathlib, re, sys
|
|
24
|
+
source = pathlib.Path(sys.argv[1])
|
|
25
|
+
version = json.loads((source / 'dependencies.json').read_text())['dependencies']['egregore-artifacts']
|
|
26
|
+
if not isinstance(version, str) or not re.fullmatch(r'[0-9]+\.[0-9]+\.[0-9]+(?:-[0-9A-Za-z.-]+)?', version):
|
|
27
|
+
raise SystemExit('artifact renderer: an exact package version is required')
|
|
28
|
+
digest = hashlib.sha256((source / 'dependencies-lock.json').read_bytes()).hexdigest()[:16]
|
|
29
|
+
print(version + '-' + digest)
|
|
30
|
+
PY
|
|
31
|
+
)" || return 1
|
|
32
|
+
managed="$ROOT/.egregore/tools/artifact-renderer/$install_id"
|
|
33
|
+
if cmp -s "$manifest_dir/dependencies.json" "$managed/package.json" && \
|
|
34
|
+
cmp -s "$manifest_dir/dependencies-lock.json" "$managed/package-lock.json" && \
|
|
35
|
+
[ -f "$managed/node_modules/egregore-artifacts/bin/cli.js" ] && \
|
|
36
|
+
[ -d "$managed/node_modules/react" ]; then
|
|
37
|
+
printf '%s\n' "$managed/node_modules/egregore-artifacts/bin/cli.js"
|
|
38
|
+
return 0
|
|
39
|
+
fi
|
|
40
|
+
fi
|
|
41
|
+
installed="$(command -v egregore-artifacts 2>/dev/null || true)"
|
|
42
|
+
if [ -n "$installed" ] && [ -f "$installed" ]; then
|
|
43
|
+
printf '%s\n' "$installed"
|
|
44
|
+
return 0
|
|
45
|
+
fi
|
|
46
|
+
echo "The artifact renderer is not installed or its dependencies are missing." >&2
|
|
47
|
+
echo "Run bash bin/artifact-renderer-install.sh from this instance, then retry." >&2
|
|
48
|
+
return 1
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
renderer="$(resolve_renderer)" || exit 1
|
|
52
|
+
if [ "${1:-}" = "--resolve" ]; then
|
|
53
|
+
[ "$#" -eq 1 ] || { echo "--resolve takes no arguments" >&2; exit 2; }
|
|
54
|
+
printf '%s\n' "$renderer"
|
|
55
|
+
exit 0
|
|
56
|
+
fi
|
|
57
|
+
exec bash "$ROOT/bin/node-run.sh" "$renderer" "$@"
|
|
@@ -110,13 +110,11 @@ preview() {
|
|
|
110
110
|
|
|
111
111
|
local render_ok=0
|
|
112
112
|
if [ -n "$composed" ]; then
|
|
113
|
-
if bash "$ROOT/bin/
|
|
114
|
-
"$ROOT/packages/egregore-artifacts/bin/cli.js" composed "$spec_file" \
|
|
113
|
+
if bash "$ROOT/bin/artifact-renderer.sh" composed "$spec_file" \
|
|
115
114
|
--source "$content_file" --verify-fidelity; then
|
|
116
115
|
render_ok=1
|
|
117
116
|
fi
|
|
118
|
-
elif bash "$ROOT/bin/
|
|
119
|
-
"$ROOT/packages/egregore-artifacts/bin/cli.js" handoff "$content_file" \
|
|
117
|
+
elif bash "$ROOT/bin/artifact-renderer.sh" handoff "$content_file" \
|
|
120
118
|
--verify-fidelity; then
|
|
121
119
|
render_ok=1
|
|
122
120
|
fi
|
|
@@ -414,21 +414,14 @@ PID_MEMORY=$!
|
|
|
414
414
|
# keep their familiar look.
|
|
415
415
|
RENDERED_HTML="$TMPD/handoff.html"
|
|
416
416
|
RENDER_OK=0
|
|
417
|
-
LOCAL_CLI="$SCRIPT_DIR/packages/egregore-artifacts/bin/cli.js"
|
|
418
417
|
FIDELITY_ARGS=(--verify-fidelity)
|
|
419
418
|
if [ "$RENDER_TYPE" = "composed" ]; then
|
|
420
419
|
FIDELITY_ARGS+=(--source "$ABS_FILE")
|
|
421
420
|
fi
|
|
422
|
-
#
|
|
423
|
-
#
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
if [ -f "$LOCAL_CLI" ] && [ -d "$SCRIPT_DIR/packages/egregore-artifacts/node_modules/react" ]; then
|
|
427
|
-
if bash "$SCRIPT_DIR/bin/node-run.sh" "$LOCAL_CLI" "$RENDER_TYPE" "${RENDER_SRC:-$ABS_FILE}" "${FIDELITY_ARGS[@]}" --output "$RENDERED_HTML" >/dev/null 2>"$TMPD/render-error"; then
|
|
428
|
-
RENDER_OK=1
|
|
429
|
-
fi
|
|
430
|
-
else
|
|
431
|
-
echo "local egregore-artifacts renderer unavailable; sending structured handoff without custom HTML" > "$TMPD/render-error"
|
|
421
|
+
# Resolve exactly as previews do, without a registry fetch. An unavailable
|
|
422
|
+
# renderer still leaves the existing structured-only handoff fallback.
|
|
423
|
+
if bash "$SCRIPT_DIR/bin/artifact-renderer.sh" "$RENDER_TYPE" "${RENDER_SRC:-$ABS_FILE}" "${FIDELITY_ARGS[@]}" --output "$RENDERED_HTML" >/dev/null 2>"$TMPD/render-error"; then
|
|
424
|
+
RENDER_OK=1
|
|
432
425
|
fi
|
|
433
426
|
|
|
434
427
|
# Step 2: build the emissary payload. If rendering succeeded AND the
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "egregore-managed-artifact-renderer",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"lockfileVersion": 3,
|
|
5
|
+
"requires": true,
|
|
6
|
+
"packages": {
|
|
7
|
+
"": {
|
|
8
|
+
"name": "egregore-managed-artifact-renderer",
|
|
9
|
+
"version": "1.0.0",
|
|
10
|
+
"dependencies": {
|
|
11
|
+
"egregore-artifacts": "0.30.0"
|
|
12
|
+
}
|
|
13
|
+
},
|
|
14
|
+
"node_modules/@json-render/core": {
|
|
15
|
+
"version": "0.16.0",
|
|
16
|
+
"resolved": "https://registry.npmjs.org/@json-render/core/-/core-0.16.0.tgz",
|
|
17
|
+
"integrity": "sha512-qQp8BB/3pWYapTGXBDSBMXRCdrC05VJPLL3drXMPX/QbUB3nuvtyXUGmAZFUz8eLUy7JImODvb3GNIq38dGzhQ==",
|
|
18
|
+
"license": "Apache-2.0",
|
|
19
|
+
"dependencies": {
|
|
20
|
+
"zod": "^4.3.6"
|
|
21
|
+
},
|
|
22
|
+
"peerDependencies": {
|
|
23
|
+
"zod": "^4.0.0"
|
|
24
|
+
}
|
|
25
|
+
},
|
|
26
|
+
"node_modules/@json-render/react": {
|
|
27
|
+
"version": "0.16.0",
|
|
28
|
+
"resolved": "https://registry.npmjs.org/@json-render/react/-/react-0.16.0.tgz",
|
|
29
|
+
"integrity": "sha512-PJQjLftGYZ5LNlA1IFww+yNOAJZRW2feEcH/L10u/8M/b/zImr9wfqQVMDyC87myoEzhyucpkQ6joISeZdKxsw==",
|
|
30
|
+
"license": "Apache-2.0",
|
|
31
|
+
"dependencies": {
|
|
32
|
+
"@json-render/core": "0.16.0"
|
|
33
|
+
},
|
|
34
|
+
"peerDependencies": {
|
|
35
|
+
"react": "^19.2.3"
|
|
36
|
+
}
|
|
37
|
+
},
|
|
38
|
+
"node_modules/egregore-artifacts": {
|
|
39
|
+
"version": "0.30.0",
|
|
40
|
+
"resolved": "https://registry.npmjs.org/egregore-artifacts/-/egregore-artifacts-0.30.0.tgz",
|
|
41
|
+
"integrity": "sha512-0mihiLED2+n3CT4/VNBW7driwTdQwNaDztJ0T5/TFZ9qJhtUAJCyeawKfnOXgjuTkwwu+d6dY/KMuZMGONGDvQ==",
|
|
42
|
+
"license": "MIT",
|
|
43
|
+
"dependencies": {
|
|
44
|
+
"@json-render/core": "^0.16.0",
|
|
45
|
+
"@json-render/react": "^0.16.0",
|
|
46
|
+
"react": "^19.2.4",
|
|
47
|
+
"react-dom": "^19.2.4",
|
|
48
|
+
"zod": "^4.3.6"
|
|
49
|
+
},
|
|
50
|
+
"bin": {
|
|
51
|
+
"egregore-artifacts": "bin/cli.js"
|
|
52
|
+
},
|
|
53
|
+
"engines": {
|
|
54
|
+
"node": ">=18"
|
|
55
|
+
}
|
|
56
|
+
},
|
|
57
|
+
"node_modules/react": {
|
|
58
|
+
"version": "19.3.0",
|
|
59
|
+
"resolved": "https://registry.npmjs.org/react/-/react-19.3.0.tgz",
|
|
60
|
+
"integrity": "sha512-E8LUcbtBWt20bbl2YoHfx4ZDBdxVTfOKtCZn9cDSJ4l6/nuoApcpIBcj47t2wZoVX8g2ZHuMHbiShgCR1T5Sog==",
|
|
61
|
+
"license": "MIT",
|
|
62
|
+
"engines": {
|
|
63
|
+
"node": ">=0.10.0"
|
|
64
|
+
}
|
|
65
|
+
},
|
|
66
|
+
"node_modules/react-dom": {
|
|
67
|
+
"version": "19.3.0",
|
|
68
|
+
"resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.3.0.tgz",
|
|
69
|
+
"integrity": "sha512-JDk8dgif51OjFoDE70+OT9ICyYr+69HlmihNwp1+Nsfbna3t5sIiCa9ZJktDmQ4/1b/rn26hIAR2uYXDMr5r0Q==",
|
|
70
|
+
"license": "MIT",
|
|
71
|
+
"dependencies": {
|
|
72
|
+
"scheduler": "^0.28.0"
|
|
73
|
+
},
|
|
74
|
+
"peerDependencies": {
|
|
75
|
+
"react": "^19.3.0"
|
|
76
|
+
}
|
|
77
|
+
},
|
|
78
|
+
"node_modules/scheduler": {
|
|
79
|
+
"version": "0.28.0",
|
|
80
|
+
"resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.28.0.tgz",
|
|
81
|
+
"integrity": "sha512-juorfCmIkIw8tT+p5BXSm6PJjQF/ycEYmKyzURCIt/RaZIhL+PulbQ9Yu2z1HdOJDdqDTlxA1+xKBmHXJsczAw==",
|
|
82
|
+
"license": "MIT"
|
|
83
|
+
},
|
|
84
|
+
"node_modules/zod": {
|
|
85
|
+
"version": "4.6.5",
|
|
86
|
+
"resolved": "https://registry.npmjs.org/zod/-/zod-4.6.5.tgz",
|
|
87
|
+
"integrity": "sha512-v5l/aFXZQeai4awLbOpSoHecE9UiMrnfx75tEXLjNonXVARxQ5mOeipTjROUchszUNCqnE+hqAMujRsRHsut2Q==",
|
|
88
|
+
"license": "MIT",
|
|
89
|
+
"funding": {
|
|
90
|
+
"url": "https://github.com/sponsors/colinhacks"
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
}
|
|
@@ -121,7 +121,7 @@ mkdir -p /tmp
|
|
|
121
121
|
} > "$_DB_MD" 2>/dev/null
|
|
122
122
|
|
|
123
123
|
# --- Publish markdown → HTML → hosted URL ---
|
|
124
|
-
# publish-artifact.sh handles HTML generation
|
|
124
|
+
# publish-artifact.sh handles HTML generation with the provisioned renderer.
|
|
125
125
|
# then uploads. Don't pre-generate HTML — that causes double-wrapping.
|
|
126
126
|
# https:// URLs are universally cmd+clickable across all terminal emulators.
|
|
127
127
|
#
|
|
@@ -233,7 +233,7 @@ else
|
|
|
233
233
|
if [ -z "$DASHBOARD_URL" ]; then
|
|
234
234
|
_DB_HTML="/tmp/egregore-artifacts/dashboard-${EGREGORE_SESSION_ID}.html"
|
|
235
235
|
mkdir -p /tmp/egregore-artifacts
|
|
236
|
-
if
|
|
236
|
+
if bash "$SCRIPT_DIR/bin/artifact-renderer.sh" document "$_DB_MD" --output "$_DB_HTML" --no-open >/dev/null 2>&1 && [ -f "$_DB_HTML" ]; then
|
|
237
237
|
DASHBOARD_URL="file://${_DB_HTML}"
|
|
238
238
|
fi
|
|
239
239
|
fi
|