@davmash/bygone 0.10.1 → 0.11.1
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 +25 -0
- package/README.md +64 -0
- package/bin/bygone.js +18 -1
- package/cli/commandSpec.js +22 -2
- package/cli/completions.js +30 -8
- package/cli/correspondence.js +71 -0
- package/cli/dependencies.js +62 -0
- package/cli/evidence.js +67 -0
- package/cli/present.js +61 -16
- package/cli/tour.js +18 -1
- package/cli/tourExport.js +1 -1
- package/completions/_bygone +15 -3
- package/completions/bygone +13 -5
- package/completions/bygone.fish +9 -0
- package/docs/change-tour-format.md +60 -6
- package/docs/correspondence.md +259 -0
- package/docs/dependencies.md +94 -0
- package/docs/evidence-review.md +163 -0
- package/docs/generating-change-tours.md +3 -0
- package/docs/present.md +3 -0
- package/docs/product-surface.md +2 -1
- package/docs/releasing.md +11 -0
- package/docs/vscode-integration.md +183 -0
- package/media/diff.worker.js +10 -9
- package/media/webview.css +1 -1
- package/media/webview.js +167 -167
- package/out/changeCorrespondence.js +739 -0
- package/out/changeTour.js +1366 -967
- package/out/dependencyGraph.js +213939 -0
- package/out/gitComparison.js +4 -0
- package/out/requirements.js +427 -0
- package/out/reviewDependencies.js +669 -0
- package/out/reviewWorkspace.js +1129 -0
- package/out/standalone-main.js +3382 -1341
- package/out/tourCoverage.js +1852 -1448
- package/package.json +2 -2
- package/schemas/change-tour-source.schema.json +48 -3
- package/web/export-runtime.json +6 -6
- package/web/index.html +13 -0
- package/web/presenter.css +81 -0
- package/web/web-host.js +23 -20
package/cli/present.js
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
|
-
const { existsSync, mkdirSync, readFile, readFileSync, realpathSync, writeFileSync } = require('fs');
|
|
1
|
+
const { existsSync, mkdirSync, readFile, readFileSync, realpathSync, statSync, writeFileSync } = require('fs');
|
|
2
2
|
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 { loadChangeCorrespondence } = require('../out/changeCorrespondence');
|
|
6
7
|
const { buildTourAuthoringCoverage, buildTourCoverageReport } = require('../out/tourCoverage.js');
|
|
7
8
|
const { buildTourWindowTitle } = require('../out/windowTitle.js');
|
|
8
9
|
const { tokenMatches } = require('./commandSpec.js');
|
|
@@ -22,7 +23,7 @@ const MIME_TYPES = new Map([
|
|
|
22
23
|
]);
|
|
23
24
|
|
|
24
25
|
async function startPresentation(args, cwd, packageRoot, options = {}) {
|
|
25
|
-
const { headRef, baseRef, tourPath, explicitHeadRef } = parsePresentArgs(args);
|
|
26
|
+
const { headRef, baseRef, tourPath, explicitHeadRef, correspondencePath } = parsePresentArgs(args);
|
|
26
27
|
const story = !options.ignoreEnvironment && process.env.BYGONE_TOUR_STORY
|
|
27
28
|
? parseChangeTourStory(JSON.parse(readFileSync(path.resolve(cwd, process.env.BYGONE_TOUR_STORY), 'utf8')))
|
|
28
29
|
: undefined;
|
|
@@ -48,6 +49,21 @@ async function startPresentation(args, cwd, packageRoot, options = {}) {
|
|
|
48
49
|
const contained = relative && relative !== '..' && !relative.startsWith('../') && !path.isAbsolute(relative);
|
|
49
50
|
manifest.localSource = { repo: pathToFileURL(root).href, tour: contained ? relative : pathToFileURL(documentPath).href };
|
|
50
51
|
}
|
|
52
|
+
const repositoryRoot = builtManifest.repository?.root || cwd;
|
|
53
|
+
const authoredCorrespondencePath = source?.correspondence
|
|
54
|
+
? path.resolve(repositoryRoot, source.correspondence)
|
|
55
|
+
: undefined;
|
|
56
|
+
const explicitCorrespondencePath = correspondencePath
|
|
57
|
+
? path.resolve(cwd, correspondencePath)
|
|
58
|
+
: undefined;
|
|
59
|
+
if (authoredCorrespondencePath && explicitCorrespondencePath
|
|
60
|
+
&& !sameActualFile(authoredCorrespondencePath, explicitCorrespondencePath)) {
|
|
61
|
+
throw new Error(`Conflicting correspondence artifacts: source.correspondence (${authoredCorrespondencePath}) and --correspondence (${explicitCorrespondencePath}) must identify the same actual file.`);
|
|
62
|
+
}
|
|
63
|
+
const correspondencePathToLoad = explicitCorrespondencePath || authoredCorrespondencePath;
|
|
64
|
+
const correspondence = correspondencePathToLoad
|
|
65
|
+
? loadChangeCorrespondence(repositoryRoot, correspondencePathToLoad, { baseOid: manifest.range.mergeBaseOid, headOid: manifest.range.headOid })
|
|
66
|
+
: null;
|
|
51
67
|
const history = createTourHistory(manifest);
|
|
52
68
|
const serializedManifest = `${JSON.stringify(manifest, null, 2)}\n`;
|
|
53
69
|
const outputPath = options.ignoreEnvironment ? undefined : process.env.BYGONE_TOUR_OUTPUT;
|
|
@@ -60,13 +76,16 @@ async function startPresentation(args, cwd, packageRoot, options = {}) {
|
|
|
60
76
|
|
|
61
77
|
const tourWindowTitle = buildTourWindowTitle(manifest, 'Bygone');
|
|
62
78
|
const presenterIndexPath = path.join(packageRoot, 'web', 'index.html');
|
|
63
|
-
let presenterIndexTemplate;
|
|
64
79
|
// Uploaded documents remain immutable, scoped to this existing repository,
|
|
65
80
|
// and addressed independently so opening one cannot mutate another tab.
|
|
66
81
|
const uploadedTours = new Map();
|
|
67
82
|
|
|
68
83
|
const server = createServer((request, response) => {
|
|
69
84
|
const requestUrl = new URL(request.url || '/', 'http://127.0.0.1');
|
|
85
|
+
if (requestUrl.pathname === '/correspondence.json') {
|
|
86
|
+
if (request.method !== 'GET') return respondJson(response, 405, { error: 'Method not allowed' });
|
|
87
|
+
return respondJson(response, correspondence ? 200 : 404, correspondence || { error: 'No correspondence supplied' });
|
|
88
|
+
}
|
|
70
89
|
if (requestUrl.pathname === '/tour/open') {
|
|
71
90
|
if (request.method !== 'POST') return respondJson(response, 405, { error: 'Method not allowed' });
|
|
72
91
|
if (!isSameOriginLoopbackRequest(request)) return respondJson(response, 403, { error: 'Forbidden' });
|
|
@@ -159,18 +178,20 @@ async function startPresentation(args, cwd, packageRoot, options = {}) {
|
|
|
159
178
|
return;
|
|
160
179
|
}
|
|
161
180
|
if (requestUrl.pathname === '/' || requestUrl.pathname === '/index.html') {
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
181
|
+
// Read HTML like the runtime assets so a rebuild cannot leave a
|
|
182
|
+
// running presentation serving old controls with new JavaScript.
|
|
183
|
+
readFile(presenterIndexPath, 'utf8', (error, template) => {
|
|
184
|
+
if (error) { respond(response, 500, 'Read failed'); return; }
|
|
185
|
+
const html = template.replace(
|
|
186
|
+
/<title>Bygone Tour<\/title>/,
|
|
187
|
+
`<title>${escapeHtml(tourWindowTitle)}</title>`
|
|
188
|
+
);
|
|
189
|
+
response.writeHead(200, {
|
|
190
|
+
'Content-Type': 'text/html; charset=utf-8',
|
|
191
|
+
'Cache-Control': 'no-store'
|
|
192
|
+
});
|
|
193
|
+
response.end(html);
|
|
172
194
|
});
|
|
173
|
-
response.end(html);
|
|
174
195
|
return;
|
|
175
196
|
}
|
|
176
197
|
const targetPath = resolveAssetPath(packageRoot, requestUrl.pathname);
|
|
@@ -203,7 +224,7 @@ async function startPresentation(args, cwd, packageRoot, options = {}) {
|
|
|
203
224
|
server.close();
|
|
204
225
|
throw new Error('Could not determine the presentation server address.');
|
|
205
226
|
}
|
|
206
|
-
const url = `http://127.0.0.1:${address.port}/?manifest=/tour.json${options.location ? serializeDocumentFragment(options.location.mode, options.location.focus) : ''}`;
|
|
227
|
+
const url = `http://127.0.0.1:${address.port}/?manifest=/tour.json${correspondence ? '&correspondence=1' : ''}${options.location ? serializeDocumentFragment(options.location.mode, options.location.focus) : ''}`;
|
|
207
228
|
if (options.announce !== false) {
|
|
208
229
|
process.stdout.write(`Bygone change tour running at ${url}\n`);
|
|
209
230
|
process.stdout.write('Press Ctrl+C to stop.\n');
|
|
@@ -225,6 +246,7 @@ function parsePresentArgs(args) {
|
|
|
225
246
|
let explicitHeadRef;
|
|
226
247
|
let baseRef;
|
|
227
248
|
let tourPath;
|
|
249
|
+
let correspondencePath;
|
|
228
250
|
for (let index = 0; index < args.length; index += 1) {
|
|
229
251
|
const arg = args[index];
|
|
230
252
|
if (tokenMatches('base', arg)) {
|
|
@@ -234,6 +256,11 @@ function parsePresentArgs(args) {
|
|
|
234
256
|
baseRef = args[++index];
|
|
235
257
|
continue;
|
|
236
258
|
}
|
|
259
|
+
if (arg === '--correspondence') {
|
|
260
|
+
if (!args[index + 1] || args[index + 1].startsWith('-')) throw new Error('--correspondence requires a file path.');
|
|
261
|
+
correspondencePath = args[++index];
|
|
262
|
+
continue;
|
|
263
|
+
}
|
|
237
264
|
if (tokenMatches('tour', arg)) {
|
|
238
265
|
if (!args[index + 1]) throw new Error(`${arg} requires a YAML file.`);
|
|
239
266
|
tourPath = args[++index];
|
|
@@ -248,7 +275,7 @@ function parsePresentArgs(args) {
|
|
|
248
275
|
headRef = arg;
|
|
249
276
|
explicitHeadRef = arg;
|
|
250
277
|
}
|
|
251
|
-
return { headRef, baseRef, tourPath, explicitHeadRef };
|
|
278
|
+
return { headRef, baseRef, tourPath, explicitHeadRef, ...(correspondencePath ? { correspondencePath } : {}) };
|
|
252
279
|
}
|
|
253
280
|
|
|
254
281
|
function resolveAssetPath(packageRoot, requestPath) {
|
|
@@ -315,6 +342,24 @@ function isSameOriginLoopbackRequest(request) {
|
|
|
315
342
|
}
|
|
316
343
|
}
|
|
317
344
|
|
|
345
|
+
function sameActualFile(first, second) {
|
|
346
|
+
if (first === second) return true;
|
|
347
|
+
try {
|
|
348
|
+
const left = statSync(first);
|
|
349
|
+
const right = statSync(second);
|
|
350
|
+
if (left.dev !== undefined && left.ino !== undefined
|
|
351
|
+
&& left.dev === right.dev && left.ino === right.ino
|
|
352
|
+
&& left.ino !== 0 && right.ino !== 0) return true;
|
|
353
|
+
} catch {
|
|
354
|
+
// Fall back to canonical paths on filesystems without usable identity metadata.
|
|
355
|
+
}
|
|
356
|
+
try {
|
|
357
|
+
return realpathSync(first) === realpathSync(second);
|
|
358
|
+
} catch {
|
|
359
|
+
return false;
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
|
|
318
363
|
function escapeHtml(text) {
|
|
319
364
|
return text
|
|
320
365
|
.replaceAll('&', '&')
|
package/cli/tour.js
CHANGED
|
@@ -34,12 +34,21 @@ function runTourCommand(args, cwd, packageRoot, output = process.stdout) {
|
|
|
34
34
|
return { action: 'schema' };
|
|
35
35
|
}
|
|
36
36
|
if (options.action === 'context') {
|
|
37
|
+
const range = options.dependencies
|
|
38
|
+
? require('../out/gitComparison.js').resolveBranchReviewRange(cwd, options.headRef, options.baseRef)
|
|
39
|
+
: undefined;
|
|
37
40
|
const context = buildChangeTourContext(cwd, {
|
|
41
|
+
range,
|
|
38
42
|
headRef: options.headRef,
|
|
39
43
|
baseRef: options.baseRef,
|
|
44
|
+
correspondencePath: options.correspondencePath ? path.resolve(cwd, options.correspondencePath) : undefined,
|
|
40
45
|
maxPatchBytes: options.maxPatchBytes,
|
|
41
46
|
maxTotalPatchBytes: options.maxTotalPatchBytes
|
|
42
47
|
});
|
|
48
|
+
if (options.dependencies) {
|
|
49
|
+
const { buildDependencyGraph } = require('../out/dependencyGraph.js');
|
|
50
|
+
context.dependencies = buildDependencyGraph(cwd, { range });
|
|
51
|
+
}
|
|
43
52
|
return writeJsonResult('change-tour context', context, options.outputPath, cwd, output);
|
|
44
53
|
}
|
|
45
54
|
|
|
@@ -147,7 +156,9 @@ function parseContextArgs(args) {
|
|
|
147
156
|
let baseRef;
|
|
148
157
|
let outputPath;
|
|
149
158
|
let maxPatchBytes;
|
|
159
|
+
let correspondencePath;
|
|
150
160
|
let maxTotalPatchBytes;
|
|
161
|
+
let dependencies = false;
|
|
151
162
|
for (let index = 0; index < args.length; index += 1) {
|
|
152
163
|
const arg = args[index];
|
|
153
164
|
if (arg === '--base' || arg === '-m' || arg === '--main') {
|
|
@@ -160,6 +171,12 @@ function parseContextArgs(args) {
|
|
|
160
171
|
outputPath = args[++index];
|
|
161
172
|
continue;
|
|
162
173
|
}
|
|
174
|
+
if (arg === '--dependencies') { dependencies = true; continue; }
|
|
175
|
+
if (arg === '--correspondence') {
|
|
176
|
+
if (!args[index + 1] || args[index + 1].startsWith('-')) throw new Error('--correspondence requires a file path.');
|
|
177
|
+
correspondencePath = args[++index];
|
|
178
|
+
continue;
|
|
179
|
+
}
|
|
163
180
|
if (arg === '--max-patch-bytes') {
|
|
164
181
|
if (!args[index + 1]) throw new Error(`${arg} requires a positive integer.`);
|
|
165
182
|
maxPatchBytes = Number.parseInt(args[++index], 10);
|
|
@@ -180,7 +197,7 @@ function parseContextArgs(args) {
|
|
|
180
197
|
if (headRef) throw new Error('tour context accepts at most one head ref.');
|
|
181
198
|
headRef = arg;
|
|
182
199
|
}
|
|
183
|
-
return { action: 'context', headRef, baseRef, outputPath, maxPatchBytes, maxTotalPatchBytes };
|
|
200
|
+
return { action: 'context', headRef, baseRef, outputPath, maxPatchBytes, maxTotalPatchBytes, ...(correspondencePath ? { correspondencePath } : {}), ...(dependencies ? { dependencies } : {}) };
|
|
184
201
|
}
|
|
185
202
|
|
|
186
203
|
function writeJsonResult(label, value, outputPath, cwd, output) {
|
package/cli/tourExport.js
CHANGED
|
@@ -78,7 +78,7 @@ function materializeTour(sourcePath, profile) {
|
|
|
78
78
|
delete manifest.localSource;
|
|
79
79
|
// A source URL is optional provenance and may carry credentials or local bindings.
|
|
80
80
|
delete manifest.sourceUrl;
|
|
81
|
-
const contentKeys = new Set(['leftContent', 'rightContent', 'content']);
|
|
81
|
+
const contentKeys = new Set(['leftContent', 'rightContent', 'content', 'text']);
|
|
82
82
|
function pack(value) {
|
|
83
83
|
if (Array.isArray(value)) return value.map(pack);
|
|
84
84
|
if (!value || typeof value !== 'object') return value;
|
package/completions/_bygone
CHANGED
|
@@ -13,7 +13,10 @@ _bygone() {
|
|
|
13
13
|
local previous="${words[CURRENT-1]}"
|
|
14
14
|
local -a root_items review_options present_options legacy_options history_options shells tour_actions
|
|
15
15
|
root_items=(
|
|
16
|
+
'evidence:Inspect, import, refresh, or present pinned review evidence'
|
|
16
17
|
'review:Review a committed branch against its merge base'
|
|
18
|
+
'dependencies:Compare static JS/TS module dependencies at committed revisions'
|
|
19
|
+
'correspondence:Import externally produced symbol correspondence evidence'
|
|
17
20
|
'completion:Print shell completion source'
|
|
18
21
|
'present:Open an app-hosted tour of a committed branch range'
|
|
19
22
|
'tour:Validate, compile, or inspect authored change tours'
|
|
@@ -41,6 +44,7 @@ _bygone() {
|
|
|
41
44
|
'-m:Set the branch-review base ref'
|
|
42
45
|
'--main:Set the branch-review base ref'
|
|
43
46
|
'--tour:Use an authored .bygone presentation'
|
|
47
|
+
'--correspondence:Use pinned symbol evidence in present or tour context'
|
|
44
48
|
'-h:Show command help'
|
|
45
49
|
'--help:Show command help'
|
|
46
50
|
)
|
|
@@ -78,16 +82,24 @@ _bygone() {
|
|
|
78
82
|
elif [[ "$words[3]" == "context" ]]; then
|
|
79
83
|
if [[ "$previous" == (--base|-m|--main) ]]; then
|
|
80
84
|
_bygone_git_refs
|
|
81
|
-
elif [[ "$previous" == "--output" || "$previous" == "-o" ]]; then
|
|
85
|
+
elif [[ "$previous" == "--output" || "$previous" == "-o" || "$previous" == "--correspondence" ]]; then
|
|
82
86
|
_files
|
|
83
87
|
else
|
|
84
|
-
compadd -- --base --output -o --max-patch-bytes --max-total-patch-bytes
|
|
88
|
+
compadd -- --base --output -o --max-patch-bytes --max-total-patch-bytes --correspondence --dependencies
|
|
85
89
|
_bygone_git_refs
|
|
86
90
|
fi
|
|
87
91
|
elif [[ "$words[3]" == "coverage" || "$words[3]" == "validate" || "$words[3]" == "compile" ]]; then
|
|
88
92
|
_files -g '*.bygone' -g '*.bygone.yaml'
|
|
89
93
|
fi
|
|
90
94
|
;;
|
|
95
|
+
dependencies)
|
|
96
|
+
if [[ "$previous" == "--output" || "$previous" == "-o" ]]; then
|
|
97
|
+
_files
|
|
98
|
+
else
|
|
99
|
+
compadd -- --base --json --output -o
|
|
100
|
+
_bygone_git_refs
|
|
101
|
+
fi
|
|
102
|
+
;;
|
|
91
103
|
review)
|
|
92
104
|
if [[ "$previous" == (--base|-m|--main) ]]; then
|
|
93
105
|
_bygone_git_refs
|
|
@@ -97,7 +109,7 @@ _bygone() {
|
|
|
97
109
|
fi
|
|
98
110
|
;;
|
|
99
111
|
present)
|
|
100
|
-
if [[ "$previous" == (--tour) ]]; then
|
|
112
|
+
if [[ "$previous" == (--tour) || "$previous" == "--correspondence" ]]; then
|
|
101
113
|
_files -g '*.bygone' -g '*.bygone.yaml'
|
|
102
114
|
elif [[ "$previous" == (--base|-m|--main) ]]; then
|
|
103
115
|
_bygone_git_refs
|
package/completions/bygone
CHANGED
|
@@ -12,7 +12,7 @@ _bygone() {
|
|
|
12
12
|
first="${COMP_WORDS[1]}"
|
|
13
13
|
|
|
14
14
|
if (( COMP_CWORD == 1 )); then
|
|
15
|
-
COMPREPLY=( $(compgen -W 'review completion present tour --diff --history --git-diff --branch-diff --test --read-only -C -h --help -v --version' -- "$cur") $(compgen -f -- "$cur") )
|
|
15
|
+
COMPREPLY=( $(compgen -W 'evidence review dependencies correspondence completion present tour --diff --history --git-diff --branch-diff --test --read-only -C -h --help -v --version' -- "$cur") $(compgen -f -- "$cur") )
|
|
16
16
|
compopt -o filenames 2>/dev/null || true
|
|
17
17
|
return
|
|
18
18
|
fi
|
|
@@ -28,17 +28,25 @@ _bygone() {
|
|
|
28
28
|
refs="$(_bygone_git_refs)"
|
|
29
29
|
if [[ "$prev" =~ ^(--base|-m|--main)$ ]]; then
|
|
30
30
|
COMPREPLY=( $(compgen -W "$refs" -- "$cur") )
|
|
31
|
-
elif [[ "$prev" == "--output" || "$prev" == "-o" ]]; then
|
|
31
|
+
elif [[ "$prev" == "--output" || "$prev" == "-o" || "$prev" == "--correspondence" ]]; then
|
|
32
32
|
COMPREPLY=( $(compgen -f -- "$cur") )
|
|
33
33
|
compopt -o filenames 2>/dev/null || true
|
|
34
34
|
else
|
|
35
|
-
COMPREPLY=( $(compgen -W '--base --output -o --max-patch-bytes --max-total-patch-bytes '"$refs" -- "$cur") )
|
|
35
|
+
COMPREPLY=( $(compgen -W '--base --output -o --max-patch-bytes --max-total-patch-bytes --correspondence --dependencies '"$refs" -- "$cur") )
|
|
36
36
|
fi
|
|
37
37
|
else
|
|
38
38
|
COMPREPLY=( $(compgen -W '--json --output -o' -- "$cur") $(compgen -f -- "$cur") )
|
|
39
39
|
compopt -o filenames 2>/dev/null || true
|
|
40
40
|
fi
|
|
41
41
|
;;
|
|
42
|
+
dependencies)
|
|
43
|
+
if [[ "$prev" == "--output" || "$prev" == "-o" ]]; then
|
|
44
|
+
COMPREPLY=( $(compgen -f -- "$cur") )
|
|
45
|
+
compopt -o filenames 2>/dev/null || true
|
|
46
|
+
else
|
|
47
|
+
COMPREPLY=( $(compgen -W '--base --json --output -o '"$(_bygone_git_refs)" -- "$cur") )
|
|
48
|
+
fi
|
|
49
|
+
;;
|
|
42
50
|
review)
|
|
43
51
|
refs="$(_bygone_git_refs)"
|
|
44
52
|
if [[ "$prev" =~ ^(--base|-m|--main)$ ]]; then
|
|
@@ -49,13 +57,13 @@ _bygone() {
|
|
|
49
57
|
;;
|
|
50
58
|
present)
|
|
51
59
|
refs="$(_bygone_git_refs)"
|
|
52
|
-
if [[ "$prev" == "--tour" ]]; then
|
|
60
|
+
if [[ "$prev" == "--tour" || "$prev" == "--correspondence" ]]; then
|
|
53
61
|
COMPREPLY=( $(compgen -f -- "$cur") )
|
|
54
62
|
compopt -o filenames 2>/dev/null || true
|
|
55
63
|
elif [[ "$prev" =~ ^(--base|-m|--main)$ ]]; then
|
|
56
64
|
COMPREPLY=( $(compgen -W "$refs" -- "$cur") )
|
|
57
65
|
else
|
|
58
|
-
COMPREPLY=( $(compgen -W '--base -m --main --tour -h --help '"$refs" -- "$cur") )
|
|
66
|
+
COMPREPLY=( $(compgen -W '--base -m --main --tour --correspondence -h --help '"$refs" -- "$cur") )
|
|
59
67
|
fi
|
|
60
68
|
;;
|
|
61
69
|
--branch-diff)
|
package/completions/bygone.fish
CHANGED
|
@@ -4,7 +4,10 @@ function __bygone_git_refs
|
|
|
4
4
|
printf "%s\n" HEAD INDEX WORKTREE
|
|
5
5
|
end
|
|
6
6
|
|
|
7
|
+
complete -c bygone -n '__fish_use_subcommand' -a evidence -r -d 'Inspect, import, refresh, or present pinned review evidence'
|
|
7
8
|
complete -c bygone -n '__fish_use_subcommand' -a review -d 'Review a committed branch against its merge base'
|
|
9
|
+
complete -c bygone -n '__fish_use_subcommand' -a dependencies -d 'Compare static JS/TS module dependencies at committed revisions'
|
|
10
|
+
complete -c bygone -n '__fish_use_subcommand' -a correspondence -r -d 'Import externally produced symbol correspondence evidence'
|
|
8
11
|
complete -c bygone -n '__fish_use_subcommand' -a completion -d 'Print shell completion source'
|
|
9
12
|
complete -c bygone -n '__fish_use_subcommand' -a present -d 'Open an app-hosted tour of a committed branch range'
|
|
10
13
|
complete -c bygone -n '__fish_use_subcommand' -a tour -d 'Validate, compile, or inspect authored change tours'
|
|
@@ -17,6 +20,11 @@ complete -c bygone -n '__fish_use_subcommand' -l read-only -d 'Open live Explore
|
|
|
17
20
|
complete -c bygone -n '__fish_use_subcommand' -s C -r -d 'Run as if Bygone started in this directory'
|
|
18
21
|
complete -c bygone -n '__fish_use_subcommand' -s h -l help -d 'Show command help'
|
|
19
22
|
complete -c bygone -n '__fish_use_subcommand' -s v -l version -d 'Show the installed version'
|
|
23
|
+
complete -c bygone -n 'string match -q "*tour context*" -- (commandline -opc)' -l dependencies -d 'Include static module dependency evidence'
|
|
24
|
+
complete -c bygone -n '__fish_seen_subcommand_from dependencies' -l base -r -a '(__bygone_git_refs)' -d 'Set the dependency comparison base'
|
|
25
|
+
complete -c bygone -n '__fish_seen_subcommand_from dependencies' -l json -d 'Print dependency evidence as JSON'
|
|
26
|
+
complete -c bygone -n '__fish_seen_subcommand_from dependencies' -l output -s o -r -d 'Write dependency evidence'
|
|
27
|
+
complete -c bygone -n '__fish_seen_subcommand_from dependencies' -a '(__bygone_git_refs)' -d 'Git ref'
|
|
20
28
|
complete -c bygone -n '__fish_seen_subcommand_from completion' -a 'zsh bash fish' -d 'Shell'
|
|
21
29
|
complete -c bygone -n '__fish_seen_subcommand_from tour' -a 'context coverage validate compile export schema' -d 'Tour action'
|
|
22
30
|
complete -c bygone -n 'string match -q "*tour context*" -- (commandline -opc)' -l base -r -a '(__bygone_git_refs)' -d 'Set the change-context base ref'
|
|
@@ -30,6 +38,7 @@ complete -c bygone -n '__fish_seen_subcommand_from review' -l base -s m -l main
|
|
|
30
38
|
complete -c bygone -n '__fish_seen_subcommand_from review' -a '(__bygone_git_refs)' -d 'Git ref'
|
|
31
39
|
complete -c bygone -n '__fish_seen_subcommand_from present' -l base -s m -l main -r -a '(__bygone_git_refs)' -d 'Set the branch-review base ref'
|
|
32
40
|
complete -c bygone -n '__fish_seen_subcommand_from present' -l tour -r -d 'Use an authored .bygone presentation'
|
|
41
|
+
complete -c bygone -l correspondence -r -d 'Use pinned symbol correspondence evidence'
|
|
33
42
|
complete -c bygone -n '__fish_seen_subcommand_from present' -a '(__bygone_git_refs)' -d 'Git ref'
|
|
34
43
|
complete -c bygone -n 'string match -q "*--branch-diff*" -- (commandline -opc)' -s b -l branch -r -a '(__bygone_git_refs)' -d 'Set the branch-review head ref'
|
|
35
44
|
complete -c bygone -n 'string match -q "*--branch-diff*" -- (commandline -opc)' -l base -s m -l main -r -a '(__bygone_git_refs)' -d 'Set the branch-review base ref'
|
|
@@ -8,16 +8,16 @@ suffix, and explicitly supplied files are validated by content rather than
|
|
|
8
8
|
rejected by extension.
|
|
9
9
|
|
|
10
10
|
An authored source is Git-backed, not portable: resolving refs and anchors
|
|
11
|
-
requires the corresponding local repository and Git objects. Version 2, 4, and
|
|
11
|
+
requires the corresponding local repository and Git objects. Version 2, 4, 5, and 6
|
|
12
12
|
compiled manifests remain bound to that repository so the presenter can load
|
|
13
13
|
live file history. Version 1 manifests remain readable as legacy portable
|
|
14
14
|
artifacts, without the mode switcher. Version 4 supports independent authored
|
|
15
15
|
tours and scene directory overviews; versions 1 and 2 remain accepted without
|
|
16
16
|
those fields.
|
|
17
17
|
|
|
18
|
-
## Version
|
|
18
|
+
## Version stability and compatibility
|
|
19
19
|
|
|
20
|
-
Format version **
|
|
20
|
+
Format version **6** is the current authoring contract. Application and document
|
|
21
21
|
versions are separate; UI fixes do not require rewriting a tour.
|
|
22
22
|
|
|
23
23
|
| Document version | Reader support | Contract |
|
|
@@ -26,8 +26,9 @@ versions are separate; UI fixes do not require rewriting a tour.
|
|
|
26
26
|
| 2 | Supported | Repository-bound manifests, real revision stacks, and endpoint walkthroughs |
|
|
27
27
|
| 3 | Retired | Remove the top-level `review` block, set source `version: 4`, and recompile |
|
|
28
28
|
| 4 | Supported | Independent authored tours and scene directory overviews; no Review Notes |
|
|
29
|
-
| 5 |
|
|
30
|
-
|
|
|
29
|
+
| 5 | Supported | Optional opening, conclusion, and chapter previews; explicit overview purpose |
|
|
30
|
+
| 6 | Use for new sources | Optional pinned symbol comparisons in walkthrough stops |
|
|
31
|
+
| Greater than 6 | Rejected with an upgrade message | Never interpreted as version 6 |
|
|
31
32
|
|
|
32
33
|
Version 4 removes the `review` field and the separate Review Notes panel.
|
|
33
34
|
Concepts, boundaries, tradeoffs, and unresolved questions belong in scene or
|
|
@@ -49,7 +50,7 @@ does not prove that the source compiles. Validate against the intended local
|
|
|
49
50
|
repository before sharing a tour.
|
|
50
51
|
|
|
51
52
|
Keep authored YAML as the editable source. Compiled JSON is generated evidence,
|
|
52
|
-
not a second authoring syntax; v2/v4/v5 manifests retain repository identity and
|
|
53
|
+
not a second authoring syntax; v2/v4/v5/v6 manifests retain repository identity and
|
|
53
54
|
resolved Git objects. Stable format support does not make missing repositories
|
|
54
55
|
or pruned objects available, and does not promise byte-identical generated
|
|
55
56
|
timestamps or presentation layout. Pin full commit IDs in `range` when the
|
|
@@ -61,6 +62,59 @@ v3 rejection, removed-field rejection, and rejection of future versions. Run
|
|
|
61
62
|
`npm test` before releasing a parser, compiler, or schema change; update those
|
|
62
63
|
checks with any new contract.
|
|
63
64
|
|
|
65
|
+
## Symbol-focused stops
|
|
66
|
+
|
|
67
|
+
Version 6 adds an optional repository-relative `correspondence` artifact and a
|
|
68
|
+
`symbol` selector on walkthrough steps. Generate the artifact as described in
|
|
69
|
+
[Symbol correspondence evidence](correspondence.md), then use an accepted
|
|
70
|
+
relation ID or one unmatched symbol ID from its inventory:
|
|
71
|
+
|
|
72
|
+
```yaml
|
|
73
|
+
version: 6
|
|
74
|
+
correspondence: evidence/symbols.json
|
|
75
|
+
# Pin range.base and range.head to the artifact's comparison.
|
|
76
|
+
anchors:
|
|
77
|
+
moved-declaration:
|
|
78
|
+
file: src/moved.py
|
|
79
|
+
revision: head
|
|
80
|
+
contains: "def transfer("
|
|
81
|
+
# Within a walkthrough scene's steps:
|
|
82
|
+
# - id: transfer
|
|
83
|
+
# title: Read the moved declaration
|
|
84
|
+
# body: Compare the complete declaration before and after the move.
|
|
85
|
+
# focus: moved-declaration
|
|
86
|
+
# symbol: { relation: relation-transfer }
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
The ordinary `focus` anchor remains required and must resolve inside the selected
|
|
90
|
+
declaration on its revision side. It preserves source navigation and existing
|
|
91
|
+
anchor validation. `symbol: { symbol: after-uncertain }` selects one unmatched
|
|
92
|
+
endpoint instead. IDs are unique across the artifact's symbol inventory; matched
|
|
93
|
+
endpoints must use their accepted relation ID. An ambiguous endpoint remains
|
|
94
|
+
one-sided, with no invented origin. Symbol stops cannot also use an image or
|
|
95
|
+
connection.
|
|
96
|
+
|
|
97
|
+
Compilation revalidates the artifact against the exact Git comparison and
|
|
98
|
+
embeds complete declaration text, source spans, revisions, and both full file
|
|
99
|
+
contexts. The source artifact path must stay inside the repository, including
|
|
100
|
+
through symlinks. Stale artifacts and selectors outside the chosen declaration
|
|
101
|
+
are errors. An accepted relation is still an inferred correspondence; behavior
|
|
102
|
+
remains unassessed.
|
|
103
|
+
|
|
104
|
+
The viewer opens the declaration comparison. **Show file context** widens to the
|
|
105
|
+
complete source and destination files, highlights both declarations, and keeps
|
|
106
|
+
the current tour stop. **Return to symbol comparison** restores the slices;
|
|
107
|
+
**Return to tour** restores the authored stop after exploring another file.
|
|
108
|
+
The compiled evidence also works in an offline HTML export without the artifact
|
|
109
|
+
or repository. Export packs repeated text once. Coverage counts only changed
|
|
110
|
+
units intersecting either selected declaration, or the single available endpoint
|
|
111
|
+
for an unmatched symbol; overlapping stops do not multiply coverage.
|
|
112
|
+
|
|
113
|
+
Existing sources and ordinary anchor stops keep their existing behavior. Live
|
|
114
|
+
presentations load the source's artifact into Symbols and Files automatically;
|
|
115
|
+
offline exports retain the selected stops and their context, rather than the
|
|
116
|
+
entire symbol inventory.
|
|
117
|
+
|
|
64
118
|
## Opening and conclusion passages
|
|
65
119
|
|
|
66
120
|
Version 5 adds optional `opening` and `conclusion` at the document root and
|