Skip to content

Commit 394f8cd

Browse files
forge: config.anchoringUi — make the Anchors tab discoverable
The Anchors tab only surfaced once a repo had anchoring enabled — but the only way to enable it is the /marks page, which had no tab/link when off. So the forge's headline feature (Bitcoin anchoring) was undiscoverable unless you knew the URL. config.anchoringUi:true now shows the Anchors tab on EVERY repo (the page already carries the Enable pitch when a repo is unanchored); default off keeps the legacy behavior (a plain forge shows no Bitcoin UI). +1 test (131).
1 parent 92a2054 commit 394f8cd

3 files changed

Lines changed: 40 additions & 3 deletions

File tree

forge/AGENT.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,12 @@ Key properties:
140140
commit cadence — the "rolling mark" that lets fast commits (fresh mirrors)
141141
coexist with slow, cheap anchoring. Default off (each commit is its own
142142
candidate state).
143+
- `anchoringUi` — when true, the repo **Anchors** tab is shown on every repo (the
144+
marks page carries the Enable pitch when a repo hasn't enabled anchoring yet).
145+
Default off, where the tab only appears once a repo has anchoring enabled —
146+
which hides the feature (you'd have to know the `/marks` URL to turn it on). A
147+
Bitcoin-forge turns this on so anchoring is discoverable; a plain forge leaves
148+
it off and shows no Bitcoin UI.
143149
- `cspConnect: [origin, …]` — extra `connect-src` origins for a login widget
144150
that talks to external identity providers.
145151
- `pushTokenTtl`, `gitHttpBackend` — see `README.md`.

forge/plugin.js

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -611,6 +611,12 @@ export async function activate(api) {
611611
// of how many commits landed since. Lets a fast commit cadence (fresh mirrors)
612612
// coexist with a slow mark cadence (one super-commit per period). See recordTip.
613613
const sparseMarks = api.config.sparseMarks === true;
614+
// Discoverability: by default the Anchors tab only appears once a repo has
615+
// anchoring enabled — which hides the feature (you'd have to know the /marks
616+
// URL to turn it on). A Bitcoin-forge sets anchoringUi:true to show the tab on
617+
// EVERY repo (the page carries the Enable pitch when off); a plain forge that
618+
// doesn't want Bitcoin UI leaves it off and stays clean.
619+
const anchoringUi = api.config.anchoringUi === true;
614620

615621
// Tier 3.5: anchoring chain, testnet4 by default. Checked FIRST, before
616622
// any other activation work. Mainnet is REFUSED at
@@ -1940,9 +1946,10 @@ ${body}
19401946
['commits', 'Commits', `${base}/commits/${branch}`],
19411947
['branches', 'Branches', `${base}/branches`],
19421948
['tags', 'Tags', `${base}/tags`],
1943-
// Anchors only surfaces once the owner enabled anchoring (the marks
1944-
// page itself always exists — it carries the Enable pitch).
1945-
...(marksEnabled(owner, name) ? [['anchors', 'Anchors', `${base}/marks`]] : []),
1949+
// Anchors: always shown when config.anchoringUi is on (discoverable — the
1950+
// marks page carries the Enable pitch when off); otherwise legacy behavior,
1951+
// surfacing only once the owner has enabled anchoring on this repo.
1952+
...((anchoringUi || marksEnabled(owner, name)) ? [['anchors', 'Anchors', `${base}/marks`]] : []),
19461953
].map(([id, label, href]) => `<a class="tab${tab === id ? ' active' : ''}" href="${href}">${label}</a>`).join('');
19471954
return `<div class="repo-strip"><div class="container">
19481955
<div class="crumb">${ICON_REPO} <a href="${prefix}/${owner}">${esc(dispOwner(owner))}</a><span class="muted">/</span><a href="${base}"><b>${esc(name)}</b></a>

forge/test.js

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2450,6 +2450,30 @@ describe('forge plugin', () => {
24502450
// ---------------------------------------------------------------------------
24512451
// Sparse marking (config.sparseMarks): the trailing UNFUNDED mark is re-targeted
24522452
// at each new tip instead of stacked, so anchoring HEAD is one tx per period.
2453+
describe('forge anchoringUi — the Anchors tab is discoverable when enabled', () => {
2454+
let jss; let base; let owner;
2455+
const tmp = fs.mkdtempSync(path.join(os.tmpdir(), 'forge-anchui-'));
2456+
const g = (args, opts = {}) => git(args, { ...opts, env: { HOME: tmp, ...(opts.env ?? {}) } });
2457+
before(async () => {
2458+
fs.writeFileSync(path.join(tmp, '.gitconfig'), '[user]\n\temail = a@e.org\n\tname = A\n[init]\n\tdefaultBranch = main\n');
2459+
jss = await startJss({ idp: true, plugins: [{ id: 'forge', module: module_, prefix: '/forge', config: { anchoringUi: true } }] });
2460+
base = jss.base;
2461+
owner = await registerAndMint(base, 'anchy');
2462+
const w = path.join(tmp, 'r'); fs.mkdirSync(w, { recursive: true });
2463+
fs.writeFileSync(path.join(w, 'a.txt'), '1\n');
2464+
await g(['init', '--quiet'], { cwd: w }); await g(['add', '-A'], { cwd: w }); await g(['commit', '--quiet', '-m', 'c1'], { cwd: w });
2465+
await g([...authFlag(owner.access_token), 'push', `${base}/forge/anchy/r.git`, 'main'], { cwd: w });
2466+
});
2467+
after(async () => { if (jss) await jss.close(); fs.rmSync(tmp, { recursive: true, force: true }); });
2468+
2469+
it('shows the Anchors tab on a repo that has NOT enabled anchoring (page carries the Enable pitch)', async () => {
2470+
const html = await (await fetch(`${base}/forge/anchy/r`)).text();
2471+
assert.match(html, /class="tab[^"]*" href="\/forge\/anchy\/r\/marks">Anchors<\/a>/, 'Anchors tab present with anchoringUi on');
2472+
const marks = await (await fetch(`${base}/forge/anchy/r/marks`)).text();
2473+
assert.match(marks, /Anchoring is not enabled/, 'the marks page shows the enable pitch');
2474+
});
2475+
});
2476+
24532477
describe('forge sparse marking (config.sparseMarks re-targets, does not stack)', () => {
24542478
let jss; let base; let owner; let wdir;
24552479
const tmp = fs.mkdtempSync(path.join(os.tmpdir(), 'forge-sparse-'));

0 commit comments

Comments
 (0)