@davmash/bygone 0.8.4 → 0.8.6

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/CHANGELOG.md CHANGED
@@ -2,6 +2,18 @@
2
2
 
3
3
  ## Unreleased
4
4
 
5
+ ## 0.8.6
6
+
7
+ - Added optional authored-tour `windowTitle` labels and context-aware desktop and VS Code window titles
8
+ - Fixed tour presenter windows so authored `windowTitle` values appear in the native title instead of staying on the default `Bygone Tour` label
9
+
10
+ ## 0.8.5
11
+
12
+ - Fixed Homebrew cask `bygone` CLI launch on Apple Silicon by routing through a bundle-aware launcher script inside the app
13
+ - Documented the macOS **“app is damaged”** workaround for unsigned desktop downloads (README, releasing docs, PR Tour Guide skill)
14
+
15
+ **macOS install:** Desktop builds are unsigned. If Gatekeeper reports the app is damaged, run `xattr -cr /Applications/Bygone.app` then open the app.
16
+
5
17
  ## 0.8.4
6
18
 
7
19
  - Clarified PR Tour Guide skill install commands for project scope and agent-specific global installs
package/README.md CHANGED
@@ -137,6 +137,19 @@ Contributors should consult the internal [product surface overview](./docs/produ
137
137
 
138
138
  The desktop app also includes `Help -> Install Command Line Tools...` for non-npm installs. Homebrew cask installs can provide the `bygone` command automatically.
139
139
 
140
+ ### macOS says the app is damaged
141
+
142
+ Downloads from GitHub or Homebrew are **unsigned** (no Apple Developer ID signature yet). macOS Gatekeeper then shows a misleading **“damaged”** dialog.
143
+
144
+ **Workaround (unsigned desktop builds):**
145
+
146
+ ```bash
147
+ xattr -cr /Applications/Bygone.app
148
+ open /Applications/Bygone.app
149
+ ```
150
+
151
+ Or right-click the app → **Open** once, or allow it under **System Settings → Privacy & Security**.
152
+
140
153
  ## Package For External Use
141
154
 
142
155
  This repo is set up for local/private packaging. A typical release flow is:
package/cli/present.js CHANGED
@@ -3,6 +3,7 @@ const { createServer } = require('http');
3
3
  const path = require('path');
4
4
  const { spawn } = require('child_process');
5
5
  const { buildChangeTourManifest, parseChangeTourStory } = require('../out/changeTour.js');
6
+ const { buildTourWindowTitle } = require('../out/windowTitle.js');
6
7
  const { tokenMatches } = require('./commandSpec.js');
7
8
  const { loadTourSource } = require('./tourFile.js');
8
9
 
@@ -39,6 +40,10 @@ async function startPresentation(args, cwd, packageRoot, options = {}) {
39
40
  process.stdout.write(`Wrote change-tour manifest to ${resolvedOutput}\n`);
40
41
  }
41
42
 
43
+ const tourWindowTitle = buildTourWindowTitle(manifest, 'Bygone');
44
+ const presenterIndexPath = path.join(packageRoot, 'web', 'index.html');
45
+ let presenterIndexTemplate;
46
+
42
47
  const server = createServer((request, response) => {
43
48
  const requestUrl = new URL(request.url || '/', 'http://127.0.0.1');
44
49
  if (requestUrl.pathname === '/tour.json') {
@@ -49,6 +54,21 @@ async function startPresentation(args, cwd, packageRoot, options = {}) {
49
54
  response.end(serializedManifest);
50
55
  return;
51
56
  }
57
+ if (requestUrl.pathname === '/' || requestUrl.pathname === '/index.html') {
58
+ if (!presenterIndexTemplate) {
59
+ presenterIndexTemplate = readFileSync(presenterIndexPath, 'utf8');
60
+ }
61
+ const html = presenterIndexTemplate.replace(
62
+ /<title>Bygone Tour<\/title>/,
63
+ `<title>${escapeHtml(tourWindowTitle)}</title>`
64
+ );
65
+ response.writeHead(200, {
66
+ 'Content-Type': 'text/html; charset=utf-8',
67
+ 'Cache-Control': 'no-store'
68
+ });
69
+ response.end(html);
70
+ return;
71
+ }
52
72
  const targetPath = resolveAssetPath(packageRoot, requestUrl.pathname);
53
73
  if (!targetPath) {
54
74
  respond(response, 404, 'Not found');
@@ -120,7 +140,7 @@ function parsePresentArgs(args) {
120
140
 
121
141
  function resolveAssetPath(packageRoot, requestPath) {
122
142
  if (requestPath === '/' || requestPath === '/index.html') {
123
- return path.join(packageRoot, 'web', 'index.html');
143
+ return null;
124
144
  }
125
145
  if (!requestPath.startsWith('/web/') && !requestPath.startsWith('/media/')) {
126
146
  return null;
@@ -160,7 +180,16 @@ function respond(response, statusCode, message) {
160
180
  response.end(message);
161
181
  }
162
182
 
183
+ function escapeHtml(text) {
184
+ return text
185
+ .replaceAll('&', '&amp;')
186
+ .replaceAll('<', '&lt;')
187
+ .replaceAll('>', '&gt;')
188
+ .replaceAll('"', '&quot;');
189
+ }
190
+
163
191
  module.exports = {
164
192
  parsePresentArgs,
165
- startPresentation
193
+ startPresentation,
194
+ escapeHtml
166
195
  };
@@ -35,11 +35,16 @@ contents, and diffs into the portable JSON manifest served by the presenter.
35
35
  Compilation fails if an anchor has no match or has multiple matches without an
36
36
  explicit `occurrence`.
37
37
 
38
+ The optional `windowTitle` sets the native window title for the tour presenter.
39
+ Use a short label such as a pull request number when several tours may be open at
40
+ once. When omitted, the presenter falls back to `title`, then a generic tour label.
41
+
38
42
  ## Structure
39
43
 
40
44
  ```yaml
41
45
  version: 1
42
46
  title: A reviewer-facing title
47
+ windowTitle: PR-1234
43
48
  sourceUrl: https://example.test/pull/123
44
49
  range:
45
50
  base: 0123456789abcdef
package/docs/releasing.md CHANGED
@@ -190,6 +190,34 @@ That path must point at a local git checkout of the tap repo. The script writes:
190
190
 
191
191
  and then commits and pushes that tap repo.
192
192
 
193
+ ## macOS Unsigned Desktop Builds
194
+
195
+ Published macOS desktop builds are currently **unsigned and not notarized**. After download, Gatekeeper often shows a misleading **“Bygone is damaged”** dialog.
196
+
197
+ ### End-user workaround
198
+
199
+ ```bash
200
+ xattr -cr /Applications/Bygone.app
201
+ open /Applications/Bygone.app
202
+ ```
203
+
204
+ Or right-click the app → **Open** once, or allow it under **System Settings → Privacy & Security**.
205
+
206
+ Document this for users in release notes when shipping desktop updates.
207
+
208
+ ### Future signing (not enabled)
209
+
210
+ Signing helpers are shelved until Apple Developer Program membership is active. They are **not** wired into `release:publish` today.
211
+
212
+ When ready to enable:
213
+
214
+ - Config: `packaging/macos/electron-builder.signing.json`
215
+ - Optional manual builds: `npm run package:desktop:mac:release`
216
+ - Verification: `npm run release:verify-macos` or `node scripts/verify-macos-signing.mjs`
217
+ - Re-enable checks in `scripts/release.mjs` (see git history)
218
+
219
+ Credentials needed later: Developer ID Application cert (`CSC_NAME` / `CSC_LINK`) plus notarization (`APPLE_API_KEY` trio, or `APPLE_ID` + app-specific password + team ID).
220
+
193
221
  ## Recommended Release Flow
194
222
 
195
223
  ### Step 1. Confirm the version
@@ -223,7 +251,6 @@ This builds:
223
251
  - macOS desktop artifacts
224
252
  - Linux AppImage
225
253
  - Windows artifacts
226
- - Homebrew style validation, if `brew` is available
227
254
 
228
255
  If local packaging is partially unavailable, use the lower-level script:
229
256
 
@@ -312,6 +339,10 @@ node ./scripts/release.mjs --skip-dmg
312
339
 
313
340
  Then fix the local DMG toolchain before attempting a full publish.
314
341
 
342
+ ### macOS says the app is damaged after install
343
+
344
+ This is expected for unsigned desktop builds. See [macOS Unsigned Desktop Builds](#macos-unsigned-desktop-builds).
345
+
315
346
  ### Windows packaging fails locally
316
347
 
317
348
  Use:
package/out/changeTour.js CHANGED
@@ -239,6 +239,9 @@ function parseChangeTourManifest(value) {
239
239
  }
240
240
  requireString(value.title, "title");
241
241
  requireString(value.generatedAt, "generatedAt");
242
+ if (value.windowTitle !== void 0) {
243
+ requireString(value.windowTitle, "windowTitle");
244
+ }
242
245
  if (value.sourceUrl !== void 0) {
243
246
  requireString(value.sourceUrl, "sourceUrl");
244
247
  }
@@ -533,8 +536,9 @@ function parseChangeTourSource(value) {
533
536
  if (!isRecord2(value) || value.version !== CHANGE_TOUR_SOURCE_VERSION) {
534
537
  throw new Error("Unsupported or missing change-tour source version.");
535
538
  }
536
- requireOnlyKeys(value, ["version", "title", "sourceUrl", "range", "anchors", "connections", "chapters", "coverage"], "source");
539
+ requireOnlyKeys(value, ["version", "title", "windowTitle", "sourceUrl", "range", "anchors", "connections", "chapters", "coverage"], "source");
537
540
  optionalString(value.title, "title");
541
+ optionalString(value.windowTitle, "windowTitle");
538
542
  optionalString(value.sourceUrl, "sourceUrl");
539
543
  if (value.range !== void 0) {
540
544
  if (!isRecord2(value.range)) throw new Error("range must be an object.");
@@ -1385,7 +1389,7 @@ var CHAPTERS = {
1385
1389
  packaging: { id: "packaging", title: "Packaging and dependencies", priority: 4 }
1386
1390
  };
1387
1391
  function buildChangeTourManifest(startPath, options = {}) {
1388
- var _a, _b, _c, _d;
1392
+ var _a, _b, _c, _d, _e;
1389
1393
  const range = resolveBranchReviewRange(startPath, options.headRef, options.baseRef);
1390
1394
  const maxFileBytes = options.maxFileBytes ?? DEFAULT_MAX_TOUR_FILE_BYTES;
1391
1395
  const maxLineBytes = options.maxLineBytes ?? DEFAULT_MAX_TOUR_LINE_BYTES;
@@ -1457,7 +1461,8 @@ function buildChangeTourManifest(startPath, options = {}) {
1457
1461
  const manifest = {
1458
1462
  version: CHANGE_TOUR_MANIFEST_VERSION,
1459
1463
  title: ((_a = options.source) == null ? void 0 : _a.title) || ((_b = options.story) == null ? void 0 : _b.title) || options.title || `${range.headRef} against ${range.baseRef}`,
1460
- sourceUrl: ((_c = options.source) == null ? void 0 : _c.sourceUrl) || ((_d = options.story) == null ? void 0 : _d.sourceUrl) || options.sourceUrl,
1464
+ windowTitle: (_c = options.source) == null ? void 0 : _c.windowTitle,
1465
+ sourceUrl: ((_d = options.source) == null ? void 0 : _d.sourceUrl) || ((_e = options.story) == null ? void 0 : _e.sourceUrl) || options.sourceUrl,
1461
1466
  generatedAt: options.generatedAt || (/* @__PURE__ */ new Date()).toISOString(),
1462
1467
  range: {
1463
1468
  baseRef: range.baseRef,