create-thally-docs 0.10.118 → 0.10.120
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/README.md +38 -8
- package/dist/{chunk-SVB25WSN.js → chunk-4KM7FPVG.js} +56 -18
- package/dist/{chunk-7UPLZRN4.js → chunk-5GOGY7E3.js} +10 -13
- package/dist/{chunk-JKC4FXSW.js → chunk-IRNJBXNU.js} +2 -2
- package/dist/{chunk-QPHUUFSH.js → chunk-JG4B5PJN.js} +19 -2
- package/dist/chunk-SJXNTYCO.js +671 -0
- package/dist/{chunk-FMVUFWZP.js → chunk-TBDAJL37.js} +28 -8
- package/dist/index.js +33 -17
- package/dist/migrate/index.d.ts +5 -1
- package/dist/migrate/index.js +6 -5
- package/dist/release.js +1 -1
- package/dist/scaffold.d.ts +4 -0
- package/dist/scaffold.js +4 -4
- package/dist/starter-sync.js +2 -2
- package/dist/starter-update.js +4 -4
- package/dist/starter-upgrade-canary.js +4 -4
- package/package.json +6 -4
- package/dist/chunk-XDSBT5EE.js +0 -356
package/README.md
CHANGED
|
@@ -13,13 +13,13 @@ cd my-docs
|
|
|
13
13
|
npm run dev
|
|
14
14
|
```
|
|
15
15
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
16
|
+
The default site does not bundle the Thally CLI or deployment tooling. Run
|
|
17
|
+
`npm run check` to validate documentation, or `npm run starter:update` to preview
|
|
18
|
+
a framework update using the current official CLI. Legacy sites that explicitly
|
|
19
|
+
install a local CLI retain their existing preview command.
|
|
20
20
|
|
|
21
|
-
The dev server starts at [http://localhost:3040](http://localhost:3040)
|
|
22
|
-
|
|
21
|
+
The dev server starts at [http://localhost:3040](http://localhost:3040). If that
|
|
22
|
+
port is occupied, run `npm run dev -- --port 3041`. A freshly scaffolded
|
|
23
23
|
site is agent-ready out of the box and scores 100/A on the built-in
|
|
24
24
|
[Agent Readiness Score](https://github.com/thallylabs/thally).
|
|
25
25
|
|
|
@@ -74,7 +74,7 @@ runs retain subprocess output for scripts and CI. These options also work with
|
|
|
74
74
|
| Command | What it does |
|
|
75
75
|
| --- | --- |
|
|
76
76
|
| `create-thally-docs <dir>` | Scaffold a new project |
|
|
77
|
-
| `create-thally-docs migrate <github-or-docs-url> [dir]` | Import a docs repository or public docs site through the shared migration engine |
|
|
77
|
+
| `create-thally-docs migrate <github-or-docs-url-or-directory> [dir]` | Import a docs repository or public docs site through the shared migration engine |
|
|
78
78
|
| `create-thally-docs check [dir] [--fix] [--ci] [--drift] [--external]` | Lint content for broken links, orphan pages, and missing frontmatter; `--external` also checks links to public hosts (bounded, warnings only) |
|
|
79
79
|
| `create-thally-docs translate --locale <code>` | Translate content into another locale |
|
|
80
80
|
|
|
@@ -88,6 +88,36 @@ destination runtime still apply. For example:
|
|
|
88
88
|
npx create-thally-docs migrate https://docs.example.com my-docs --max-pages 1500 --yes
|
|
89
89
|
```
|
|
90
90
|
|
|
91
|
+
A local checkout works without making a private repository public:
|
|
92
|
+
|
|
93
|
+
```bash
|
|
94
|
+
npx create-thally-docs migrate "../private docs" my-docs --platform mintlify --yes
|
|
95
|
+
npx create-thally-docs migrate https://docs.example.com my-docs --openapi https://docs.example.com/openapi.json --yes
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
Local sources are supported by the local CLI (`thally migrate` forwards the same
|
|
99
|
+
arguments). The selected input and output must be separate directories. The
|
|
100
|
+
importer snapshots documentation inputs without executing configuration; it skips
|
|
101
|
+
hidden files, dependency directories and symlinks that escape the selected root.
|
|
102
|
+
The Cloud and MCP URL adapters do not gain access to local paths or `file://` URLs.
|
|
103
|
+
|
|
104
|
+
Website migration restores publisher-provided embedded OpenAPI operations and
|
|
105
|
+
can discover a single linked `openapi.json`/`openapi.yaml` specification. Supply
|
|
106
|
+
`--openapi <https-url>` when the source does not expose one, or links several.
|
|
107
|
+
Only unambiguous operation routes are bound to crawled pages; their original
|
|
108
|
+
prose and URLs stay intact, and generated API navigation excludes those operations.
|
|
109
|
+
Markdown mirror links retain `.md`; machine indexes and spec links use the new
|
|
110
|
+
site's equivalent routes. The migration report identifies unresolved internal links
|
|
111
|
+
and unsupported frontmatter that need review. Supported code-fence labels,
|
|
112
|
+
line numbers, wrapping, focus and highlights remain portable.
|
|
113
|
+
|
|
114
|
+
An in-place import (`--into <dir>`) preserves authored files that conflict with
|
|
115
|
+
incoming content and lists them in `migration-report.json`; validation fails until
|
|
116
|
+
you resolve those conflicts. Authored navigation is merged. Untouched sample
|
|
117
|
+
navigation is replaced only after comparison with the project's verified immutable
|
|
118
|
+
starter archive and unchanged sample content. If provenance cannot be proved, the
|
|
119
|
+
existing navigation is preserved and the report explains why.
|
|
120
|
+
|
|
91
121
|
Interactive migrations ask whether the source is Mintlify, Docusaurus, Fern, or
|
|
92
122
|
another auto-detected platform. When automatic detection receives a live
|
|
93
123
|
website URL, the CLI recommends its source GitHub repository and requires
|
|
@@ -111,7 +141,7 @@ embedded by Mintlify when it is available, with bounded same-site crawling as a
|
|
|
111
141
|
fallback.
|
|
112
142
|
|
|
113
143
|
Migrated OpenAPI specs are written to `openapi/`, not `public/` (which the host
|
|
114
|
-
serves as-is). `--into` never deletes files: an older copy of a spec already in
|
|
144
|
+
serves as-is). `--into` never deletes authored files; only verified unchanged starter samples may be removed: an older copy of a spec already in
|
|
115
145
|
`public/` stays publicly downloadable (a `public/openapi.json` even answers
|
|
116
146
|
`/openapi.json` in place of the filtered spec), so the migration lists such files and
|
|
117
147
|
`thally check` warns about them until you delete them manually.
|
|
@@ -9,7 +9,7 @@ import {
|
|
|
9
9
|
} from "./chunk-J7255UQA.js";
|
|
10
10
|
import {
|
|
11
11
|
downloadStarter
|
|
12
|
-
} from "./chunk-
|
|
12
|
+
} from "./chunk-IRNJBXNU.js";
|
|
13
13
|
import {
|
|
14
14
|
terminal
|
|
15
15
|
} from "./chunk-L2YCVQBR.js";
|
|
@@ -22,6 +22,7 @@ import { resolve as resolve2 } from "path";
|
|
|
22
22
|
import { execFileSync, execSync, spawn } from "child_process";
|
|
23
23
|
import { existsSync, readFileSync } from "fs";
|
|
24
24
|
import { join, resolve } from "path";
|
|
25
|
+
import semver from "semver";
|
|
25
26
|
function slugify(name) {
|
|
26
27
|
return name.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/(^-|-$)/g, "");
|
|
27
28
|
}
|
|
@@ -34,7 +35,7 @@ async function runProjectCommand(command, args, cwd, timeout, onProgress) {
|
|
|
34
35
|
stdio: isQuiet ? ["ignore", "pipe", "pipe"] : "inherit",
|
|
35
36
|
// Windows resolves npm via a .cmd shim; command and arguments here are
|
|
36
37
|
// fixed by the toolchain, never interpolated from imported content.
|
|
37
|
-
shell: process.platform === "win32" &&
|
|
38
|
+
shell: process.platform === "win32" && ["npm", "pnpm", "yarn"].includes(command)
|
|
38
39
|
});
|
|
39
40
|
let tail = Buffer.alloc(0);
|
|
40
41
|
let omitted = false;
|
|
@@ -121,18 +122,51 @@ async function initGit(targetDir) {
|
|
|
121
122
|
terminal.warn("Could not finish Git setup. Run git status in the project directory, fix the reported issue, then retry the commit.");
|
|
122
123
|
}
|
|
123
124
|
}
|
|
124
|
-
|
|
125
|
+
function detectPackageManager(targetDir, requested, userAgent = process.env.npm_config_user_agent) {
|
|
126
|
+
if (requested) return requested;
|
|
127
|
+
if (existsSync(join(targetDir, "pnpm-lock.yaml"))) return "pnpm";
|
|
128
|
+
if (existsSync(join(targetDir, "yarn.lock"))) return "yarn";
|
|
129
|
+
if (userAgent?.startsWith("pnpm/")) return "pnpm";
|
|
130
|
+
if (userAgent?.startsWith("yarn/")) return "yarn";
|
|
131
|
+
return "npm";
|
|
132
|
+
}
|
|
133
|
+
function dependencyInstallArguments(targetDir, manager) {
|
|
134
|
+
if (manager !== "npm") return ["install"];
|
|
135
|
+
return [
|
|
136
|
+
existsSync(join(targetDir, "package-lock.json")) ? "ci" : "install",
|
|
137
|
+
"--no-audit",
|
|
138
|
+
"--no-fund",
|
|
139
|
+
"--progress=false"
|
|
140
|
+
];
|
|
141
|
+
}
|
|
142
|
+
function assertProjectNodeVersion(targetDir, nodeVersion = process.versions.node) {
|
|
143
|
+
const manifest = JSON.parse(readFileSync(join(targetDir, "package.json"), "utf8"));
|
|
144
|
+
const range = manifest.engines?.node;
|
|
145
|
+
if (range === void 0) return;
|
|
146
|
+
if (typeof range !== "string" || !semver.validRange(range)) {
|
|
147
|
+
throw new Error("The documentation project declares an invalid Node.js engine range.");
|
|
148
|
+
}
|
|
149
|
+
if (!semver.satisfies(nodeVersion, range)) {
|
|
150
|
+
throw new Error(`This documentation project requires Node.js ${range}; you are using ${nodeVersion}. Switch to a supported Node.js version and retry installation. Your project files and lockfile are preserved.`);
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
async function installDeps(targetDir, requested) {
|
|
154
|
+
const manager = detectPackageManager(targetDir, requested);
|
|
155
|
+
const args = dependencyInstallArguments(targetDir, manager);
|
|
125
156
|
try {
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
157
|
+
assertProjectNodeVersion(targetDir);
|
|
158
|
+
await terminal.step("Install dependencies", (update) => runProjectCommand(
|
|
159
|
+
manager,
|
|
160
|
+
args,
|
|
161
|
+
targetDir,
|
|
162
|
+
void 0,
|
|
163
|
+
(message) => update(`Install dependencies: ${message}`)
|
|
164
|
+
), "Dependencies installed");
|
|
133
165
|
} catch (error) {
|
|
134
166
|
const failure = error;
|
|
135
167
|
if (failure.output?.trim()) terminal.error(failure.output.trimEnd());
|
|
168
|
+
else terminal.error(failure.message);
|
|
169
|
+
terminal.warn(`Installation did not complete. Your content and lockfile were kept. Retry: cd ${quoteDirectory(targetDir)} && ${manager} ${args.join(" ")}. If a package is incomplete, remove only node_modules before retrying.`);
|
|
136
170
|
throw error;
|
|
137
171
|
}
|
|
138
172
|
}
|
|
@@ -148,18 +182,22 @@ function declaresThallyCli(directory) {
|
|
|
148
182
|
return false;
|
|
149
183
|
}
|
|
150
184
|
}
|
|
151
|
-
function devCommand(directory, needsInstall = false) {
|
|
185
|
+
function devCommand(directory, needsInstall = false, requested) {
|
|
152
186
|
const binary = join(directory, "node_modules", ".bin", "thally");
|
|
153
187
|
const hasLocalCli = needsInstall ? declaresThallyCli(directory) : existsSync(binary) || existsSync(`${binary}.cmd`);
|
|
154
|
-
|
|
188
|
+
const manager = detectPackageManager(directory, requested);
|
|
189
|
+
if (!hasLocalCli) return `${manager} run dev`;
|
|
190
|
+
return manager === "npm" ? "npx thally dev" : manager === "pnpm" ? "pnpm exec thally dev" : "yarn thally dev";
|
|
155
191
|
}
|
|
156
|
-
function previewCommand(directory, needsInstall = false) {
|
|
157
|
-
|
|
192
|
+
function previewCommand(directory, needsInstall = false, requested) {
|
|
193
|
+
const manager = detectPackageManager(directory, requested);
|
|
194
|
+
const install = manager === "npm" && existsSync(join(directory, "package-lock.json")) ? "npm ci" : `${manager} install`;
|
|
195
|
+
return `cd ${quoteDirectory(directory)} && ${needsInstall ? `${install} && ` : ""}${devCommand(directory, needsInstall, requested)}`;
|
|
158
196
|
}
|
|
159
197
|
function logo(version) {
|
|
160
198
|
terminal.intro("init", version, "Build and publish docs for people and AI tools.");
|
|
161
199
|
}
|
|
162
|
-
function success(projectDir, projectName, dependenciesInstalled) {
|
|
200
|
+
function success(projectDir, projectName, dependenciesInstalled, requested) {
|
|
163
201
|
terminal.detail("Project", projectName);
|
|
164
202
|
terminal.detail("Output", projectDir);
|
|
165
203
|
terminal.section("Make it yours", [
|
|
@@ -168,7 +206,7 @@ function success(projectDir, projectName, dependenciesInstalled) {
|
|
|
168
206
|
"src/data/site.ts Name, links, and branding"
|
|
169
207
|
]);
|
|
170
208
|
terminal.outro("Your docs project is ready. The dev server will print your preview URL.");
|
|
171
|
-
terminal.nextAction("Preview locally", previewCommand(projectDir, !dependenciesInstalled));
|
|
209
|
+
terminal.nextAction("Preview locally", previewCommand(projectDir, !dependenciesInstalled, requested));
|
|
172
210
|
}
|
|
173
211
|
|
|
174
212
|
// src/scaffold.ts
|
|
@@ -221,12 +259,12 @@ async function scaffold(options) {
|
|
|
221
259
|
let dependenciesInstalled = false;
|
|
222
260
|
if (doInstall) {
|
|
223
261
|
try {
|
|
224
|
-
await installDeps(targetDir);
|
|
262
|
+
await installDeps(targetDir, options.packageManager);
|
|
225
263
|
dependenciesInstalled = true;
|
|
226
264
|
} catch (error) {
|
|
227
265
|
const exitCode = error.exitCode;
|
|
228
266
|
if (!continueOnInstallFailure || exitCode === 130 || exitCode === 143) throw error;
|
|
229
|
-
terminal.warn(
|
|
267
|
+
terminal.warn("Dependency installation failed. The project was created; use the recovery command above to finish.");
|
|
230
268
|
}
|
|
231
269
|
}
|
|
232
270
|
await initGit(targetDir);
|
|
@@ -1,20 +1,21 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
3
|
downloadStarter
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-IRNJBXNU.js";
|
|
5
5
|
import {
|
|
6
6
|
applyStarterRuntimeSyncPlan,
|
|
7
|
+
areStarterFileContentsEquivalent,
|
|
7
8
|
captureTargetPrecondition,
|
|
8
9
|
mergeStarterOwnershipContracts,
|
|
9
10
|
parseStarterReleaseManifest,
|
|
10
11
|
planStarterRuntimeSync,
|
|
11
12
|
readStarterReleaseManifest,
|
|
12
13
|
starterManifestSha256
|
|
13
|
-
} from "./chunk-
|
|
14
|
+
} from "./chunk-JG4B5PJN.js";
|
|
14
15
|
import {
|
|
15
16
|
STABLE_SCAFFOLD_RELEASE,
|
|
16
17
|
SUPPORTED_SCAFFOLD_RELEASES
|
|
17
|
-
} from "./chunk-
|
|
18
|
+
} from "./chunk-TBDAJL37.js";
|
|
18
19
|
|
|
19
20
|
// src/starter-update.ts
|
|
20
21
|
import {
|
|
@@ -36,10 +37,6 @@ var STRUCTURED_MANUAL_REVIEW_PATHS = /* @__PURE__ */ new Set([
|
|
|
36
37
|
"package-lock.json"
|
|
37
38
|
]);
|
|
38
39
|
var MISSING_JSON_VALUE = /* @__PURE__ */ Symbol("missing-json-value");
|
|
39
|
-
function hasSameBytes(left, right) {
|
|
40
|
-
if (!left || !right) return left === right;
|
|
41
|
-
return left.equals(right);
|
|
42
|
-
}
|
|
43
40
|
function isJsonObject(value) {
|
|
44
41
|
return value !== MISSING_JSON_VALUE && value !== null && typeof value === "object" && !Array.isArray(value);
|
|
45
42
|
}
|
|
@@ -121,10 +118,10 @@ function resolveManualReviewMutations(paths, downstreamFiles, previousReleaseFil
|
|
|
121
118
|
const downstream = downstreamFiles.get(path);
|
|
122
119
|
const previous = previousReleaseFiles.get(path);
|
|
123
120
|
const target = targetReleaseFiles.get(path);
|
|
124
|
-
if (
|
|
121
|
+
if (areStarterFileContentsEquivalent(path, previous, target) || areStarterFileContentsEquivalent(path, downstream, target)) {
|
|
125
122
|
continue;
|
|
126
123
|
}
|
|
127
|
-
if (
|
|
124
|
+
if (areStarterFileContentsEquivalent(path, downstream, previous)) {
|
|
128
125
|
if (target) mutations.writeFiles.set(path, target);
|
|
129
126
|
else mutations.deletePaths.push(path);
|
|
130
127
|
continue;
|
|
@@ -136,7 +133,7 @@ function resolveManualReviewMutations(paths, downstreamFiles, previousReleaseFil
|
|
|
136
133
|
target
|
|
137
134
|
});
|
|
138
135
|
if (merged.content) {
|
|
139
|
-
if (!
|
|
136
|
+
if (!areStarterFileContentsEquivalent(path, downstream, merged.content)) {
|
|
140
137
|
mutations.writeFiles.set(path, merged.content);
|
|
141
138
|
}
|
|
142
139
|
continue;
|
|
@@ -343,7 +340,7 @@ async function resolveStarterUpdateBase(options) {
|
|
|
343
340
|
assertRecoveryPackages(options.targetDir, baselineDir, baseline.packages);
|
|
344
341
|
return { release, recoveredProvenance: true, manifestSha256 };
|
|
345
342
|
}
|
|
346
|
-
throw new Error("The project starter manifest is edited, unknown, or has no verified published framework baseline; refusing to update.");
|
|
343
|
+
throw new Error("The project starter manifest is edited, unknown, or has no verified published framework baseline; refusing to update. If this project was created by a newer release, retry with npx --yes --package=@thallylabs/cli@latest thally starter update. Keep starter-release.json unchanged.");
|
|
347
344
|
} finally {
|
|
348
345
|
rmSync(workspace, { recursive: true, force: true });
|
|
349
346
|
}
|
|
@@ -354,7 +351,7 @@ function assertForwardRelease(previous, target, releases) {
|
|
|
354
351
|
}
|
|
355
352
|
if (previous.source.commitSha === target.source.commitSha) return;
|
|
356
353
|
if (previous.starterVersion > target.starterVersion) {
|
|
357
|
-
throw new Error("The installed CLI does not contain a newer starter release.");
|
|
354
|
+
throw new Error("The installed CLI does not contain a newer starter release. Retry with npx --yes --package=@thallylabs/cli@latest thally starter update.");
|
|
358
355
|
}
|
|
359
356
|
if (previous.starterVersion === target.starterVersion) {
|
|
360
357
|
const targetIndex = releases.findIndex(
|
|
@@ -364,7 +361,7 @@ function assertForwardRelease(previous, target, releases) {
|
|
|
364
361
|
(release) => release.source.commitSha === previous.source.commitSha
|
|
365
362
|
);
|
|
366
363
|
if (targetIndex === -1 || previousIndex === -1 || previousIndex <= targetIndex) {
|
|
367
|
-
throw new Error("The installed CLI does not contain a newer starter release.");
|
|
364
|
+
throw new Error("The installed CLI does not contain a newer starter release. Retry with npx --yes --package=@thallylabs/cli@latest thally starter update.");
|
|
368
365
|
}
|
|
369
366
|
}
|
|
370
367
|
}
|
|
@@ -4,10 +4,10 @@ import {
|
|
|
4
4
|
} from "./chunk-L2YCVQBR.js";
|
|
5
5
|
import {
|
|
6
6
|
readStarterReleaseManifest
|
|
7
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-JG4B5PJN.js";
|
|
8
8
|
import {
|
|
9
9
|
STABLE_SCAFFOLD_RELEASE
|
|
10
|
-
} from "./chunk-
|
|
10
|
+
} from "./chunk-TBDAJL37.js";
|
|
11
11
|
|
|
12
12
|
// src/download.ts
|
|
13
13
|
import { Readable, Transform, pipeline } from "stream";
|
|
@@ -1,10 +1,26 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
3
|
STABLE_SCAFFOLD_RELEASE
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-TBDAJL37.js";
|
|
5
5
|
|
|
6
6
|
// src/starter-sync.ts
|
|
7
7
|
import { createHash } from "crypto";
|
|
8
|
+
|
|
9
|
+
// src/starter-file-comparison.ts
|
|
10
|
+
var textPolicies = /* @__PURE__ */ new Set([".gitignore", ".gitattributes"]);
|
|
11
|
+
function areStarterFileContentsEquivalent(path, left, right) {
|
|
12
|
+
if (!left || !right) return left === right;
|
|
13
|
+
if (left.equals(right)) return true;
|
|
14
|
+
const filename = path.split(/[\\/]/).at(-1) ?? "";
|
|
15
|
+
if (!/\.(?:[cm]?[jt]sx?|jsonc?|mdx?|ya?ml|css|html|svg|txt)$/.test(filename) && !textPolicies.has(filename)) return false;
|
|
16
|
+
if (left.includes(0) || right.includes(0)) return false;
|
|
17
|
+
const leftText = left.toString("utf8");
|
|
18
|
+
const rightText = right.toString("utf8");
|
|
19
|
+
if (!Buffer.from(leftText).equals(left) || !Buffer.from(rightText).equals(right)) return false;
|
|
20
|
+
return leftText.replace(/\r\n/g, "\n") === rightText.replace(/\r\n/g, "\n");
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
// src/starter-sync.ts
|
|
8
24
|
import {
|
|
9
25
|
copyFileSync,
|
|
10
26
|
existsSync,
|
|
@@ -249,7 +265,7 @@ function collectFiles(root, contract, desiredOwnership) {
|
|
|
249
265
|
}
|
|
250
266
|
function sameFile(left, right) {
|
|
251
267
|
if (!left || !right) return left === right;
|
|
252
|
-
return readFileSync(left)
|
|
268
|
+
return areStarterFileContentsEquivalent(left, readFileSync(left), readFileSync(right));
|
|
253
269
|
}
|
|
254
270
|
function fileSha256(path) {
|
|
255
271
|
return createHash("sha256").update(readFileSync(path)).digest("hex");
|
|
@@ -520,6 +536,7 @@ function applyStarterRuntimeSyncPlan(newStarterDir, targetDir, plan, ownership,
|
|
|
520
536
|
}
|
|
521
537
|
|
|
522
538
|
export {
|
|
539
|
+
areStarterFileContentsEquivalent,
|
|
523
540
|
parseStarterOwnershipContract,
|
|
524
541
|
mergeStarterOwnershipContracts,
|
|
525
542
|
starterManifestSha256,
|