stego-cli 0.1.6 → 0.2.0
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/.markdownlint.manuscript.json +8 -0
- package/README.md +3 -1
- package/dist/stego-cli.js +284 -17
- package/package.json +7 -4
- package/projects/fiction-example/.markdownlint.json +2 -1
- package/projects/fiction-example/.markdownlint.manuscript.json +8 -0
- package/projects/fiction-example/package.json +1 -0
- package/projects/fiction-example/spine/characters.md +4 -0
- package/projects/fiction-example/spine/locations.md +4 -0
- package/projects/fiction-example/spine/sources.md +3 -0
- package/projects/stego-docs/manuscript/400-everyday-workflow-and-commands.md +3 -0
- package/projects/stego-docs/package.json +1 -0
- package/projects/stego-docs/spine/commands.md +16 -0
- package/projects/stego-docs/spine/concepts.md +10 -0
- package/projects/stego-docs/spine/configuration.md +8 -0
- package/projects/stego-docs/spine/integrations.md +6 -0
- package/projects/stego-docs/spine/workflows.md +6 -0
package/README.md
CHANGED
|
@@ -19,6 +19,7 @@ npm install
|
|
|
19
19
|
stego list-projects
|
|
20
20
|
stego validate --project fiction-example
|
|
21
21
|
stego build --project fiction-example
|
|
22
|
+
stego new --project fiction-example
|
|
22
23
|
```
|
|
23
24
|
|
|
24
25
|
`stego init` scaffolds two example projects:
|
|
@@ -26,7 +27,7 @@ stego build --project fiction-example
|
|
|
26
27
|
- `stego-docs` (the full documentation project)
|
|
27
28
|
- `fiction-example` (a fiction-oriented demo with rich Spine usage)
|
|
28
29
|
|
|
29
|
-
For day-to-day editing, open a project folder in VS Code (for example `projects/stego-docs`) and use the Stego VS Code extension, which is the official UI for Stego projects.
|
|
30
|
+
For day-to-day editing, open a project folder in VS Code (for example `projects/stego-docs`) and use the [Stego VS Code extension](https://github.com/matt-gold/stego-extension), which is the official UI for Stego projects.
|
|
30
31
|
|
|
31
32
|
## Full documentation
|
|
32
33
|
|
|
@@ -48,6 +49,7 @@ Run commands from the workspace root and target a project with `--project`.
|
|
|
48
49
|
```bash
|
|
49
50
|
stego list-projects
|
|
50
51
|
stego new-project --project my-book --title "My Book"
|
|
52
|
+
stego new --project fiction-example
|
|
51
53
|
stego validate --project fiction-example
|
|
52
54
|
stego build --project fiction-example
|
|
53
55
|
stego check-stage --project fiction-example --stage revise
|
package/dist/stego-cli.js
CHANGED
|
@@ -16,6 +16,7 @@ const STATUS_RANK = {
|
|
|
16
16
|
final: 4
|
|
17
17
|
};
|
|
18
18
|
const RESERVED_COMMENT_PREFIX = "CMT";
|
|
19
|
+
const DEFAULT_NEW_MANUSCRIPT_SLUG = "new-document";
|
|
19
20
|
const ROOT_CONFIG_FILENAME = "stego.config.json";
|
|
20
21
|
const PROSE_FONT_PROMPT = "Switch workspace to proportional (prose-style) font? (recommended)";
|
|
21
22
|
const SCAFFOLD_GITIGNORE_CONTENT = `node_modules/
|
|
@@ -54,6 +55,7 @@ stego validate --project fiction-example
|
|
|
54
55
|
stego build --project fiction-example
|
|
55
56
|
stego check-stage --project fiction-example --stage revise
|
|
56
57
|
stego export --project fiction-example --format md
|
|
58
|
+
stego new --project fiction-example
|
|
57
59
|
\`\`\`
|
|
58
60
|
|
|
59
61
|
## Work inside one project
|
|
@@ -77,6 +79,12 @@ This keeps your editor context focused and applies the project's recommended ext
|
|
|
77
79
|
\`\`\`bash
|
|
78
80
|
stego new-project --project my-book --title "My Book"
|
|
79
81
|
\`\`\`
|
|
82
|
+
|
|
83
|
+
## Add a new manuscript file
|
|
84
|
+
|
|
85
|
+
\`\`\`bash
|
|
86
|
+
stego new --project fiction-example
|
|
87
|
+
\`\`\`
|
|
80
88
|
`;
|
|
81
89
|
const PROSE_MARKDOWN_EDITOR_SETTINGS = {
|
|
82
90
|
"[markdown]": {
|
|
@@ -117,6 +125,13 @@ async function main() {
|
|
|
117
125
|
activateWorkspace(options);
|
|
118
126
|
await createProject(readStringOption(options, "project"), readStringOption(options, "title"));
|
|
119
127
|
return;
|
|
128
|
+
case "new": {
|
|
129
|
+
activateWorkspace(options);
|
|
130
|
+
const project = resolveProject(readStringOption(options, "project"));
|
|
131
|
+
const createdPath = createNewManuscript(project, readStringOption(options, "i"));
|
|
132
|
+
logLine(`Created manuscript: ${createdPath}`);
|
|
133
|
+
return;
|
|
134
|
+
}
|
|
120
135
|
case "validate": {
|
|
121
136
|
activateWorkspace(options);
|
|
122
137
|
const project = resolveProject(readStringOption(options, "project"));
|
|
@@ -157,6 +172,18 @@ async function main() {
|
|
|
157
172
|
}
|
|
158
173
|
return;
|
|
159
174
|
}
|
|
175
|
+
case "lint": {
|
|
176
|
+
activateWorkspace(options);
|
|
177
|
+
const project = resolveProject(readStringOption(options, "project"));
|
|
178
|
+
const selection = resolveLintSelection(options);
|
|
179
|
+
const result = runProjectLint(project, selection);
|
|
180
|
+
printReport(result.issues);
|
|
181
|
+
exitIfErrors(result.issues);
|
|
182
|
+
const scopeLabel = formatLintSelection(selection);
|
|
183
|
+
const fileLabel = result.fileCount === 1 ? "file" : "files";
|
|
184
|
+
logLine(`Lint passed for '${project.id}' (${scopeLabel}, ${result.fileCount} ${fileLabel}).`);
|
|
185
|
+
return;
|
|
186
|
+
}
|
|
160
187
|
case "export": {
|
|
161
188
|
activateWorkspace(options);
|
|
162
189
|
const project = resolveProject(readStringOption(options, "project"));
|
|
@@ -382,18 +409,36 @@ function parseArgs(argv) {
|
|
|
382
409
|
const options = { _: [] };
|
|
383
410
|
for (let i = 0; i < rest.length; i += 1) {
|
|
384
411
|
const token = rest[i];
|
|
385
|
-
if (
|
|
386
|
-
options._.push(
|
|
412
|
+
if (token === "--") {
|
|
413
|
+
options._.push(...rest.slice(i + 1));
|
|
414
|
+
break;
|
|
415
|
+
}
|
|
416
|
+
if (token.startsWith("--")) {
|
|
417
|
+
const key = token.slice(2);
|
|
418
|
+
const next = rest[i + 1];
|
|
419
|
+
if (!next || next.startsWith("-")) {
|
|
420
|
+
options[key] = true;
|
|
421
|
+
continue;
|
|
422
|
+
}
|
|
423
|
+
options[key] = next;
|
|
424
|
+
i += 1;
|
|
387
425
|
continue;
|
|
388
426
|
}
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
427
|
+
if (token.startsWith("-") && token.length > 1) {
|
|
428
|
+
const key = token.slice(1);
|
|
429
|
+
const next = rest[i + 1];
|
|
430
|
+
if (!next || next.startsWith("-")) {
|
|
431
|
+
options[key] = true;
|
|
432
|
+
continue;
|
|
433
|
+
}
|
|
434
|
+
options[key] = next;
|
|
435
|
+
i += 1;
|
|
436
|
+
continue;
|
|
437
|
+
}
|
|
438
|
+
if (!token.startsWith("--")) {
|
|
439
|
+
options._.push(token);
|
|
393
440
|
continue;
|
|
394
441
|
}
|
|
395
|
-
options[key] = next;
|
|
396
|
-
i += 1;
|
|
397
442
|
}
|
|
398
443
|
return { command, options };
|
|
399
444
|
}
|
|
@@ -464,6 +509,7 @@ async function initWorkspace(options) {
|
|
|
464
509
|
writeScaffoldGitignore(targetRoot, copiedPaths);
|
|
465
510
|
writeScaffoldReadme(targetRoot, copiedPaths);
|
|
466
511
|
copyTemplateAsset(".markdownlint.json", targetRoot, copiedPaths);
|
|
512
|
+
copyTemplateAsset(".markdownlint.manuscript.json", targetRoot, copiedPaths);
|
|
467
513
|
copyTemplateAsset(".cspell.json", targetRoot, copiedPaths);
|
|
468
514
|
copyTemplateAsset(ROOT_CONFIG_FILENAME, targetRoot, copiedPaths);
|
|
469
515
|
copyTemplateAsset("projects", targetRoot, copiedPaths);
|
|
@@ -594,6 +640,7 @@ function rewriteTemplateProjectPackageScripts(targetRoot) {
|
|
|
594
640
|
scripts.build = "npx --no-install stego build";
|
|
595
641
|
scripts["check-stage"] = "npx --no-install stego check-stage";
|
|
596
642
|
scripts.export = "npx --no-install stego export";
|
|
643
|
+
scripts.new = "npx --no-install stego new";
|
|
597
644
|
projectPackage.scripts = scripts;
|
|
598
645
|
fs.writeFileSync(packageJsonPath, `${JSON.stringify(projectPackage, null, 2)}\n`, "utf8");
|
|
599
646
|
ensureProjectExtensionsRecommendations(projectRoot);
|
|
@@ -684,6 +731,8 @@ function writeInitRootPackageJson(targetRoot) {
|
|
|
684
731
|
scripts: {
|
|
685
732
|
"list-projects": "stego list-projects",
|
|
686
733
|
"new-project": "stego new-project",
|
|
734
|
+
new: "stego new",
|
|
735
|
+
lint: "stego lint",
|
|
687
736
|
validate: "stego validate",
|
|
688
737
|
build: "stego build",
|
|
689
738
|
"check-stage": "stego check-stage",
|
|
@@ -698,7 +747,7 @@ function writeInitRootPackageJson(targetRoot) {
|
|
|
698
747
|
fs.writeFileSync(path.join(targetRoot, "package.json"), `${JSON.stringify(manifest, null, 2)}\n`, "utf8");
|
|
699
748
|
}
|
|
700
749
|
function printUsage() {
|
|
701
|
-
console.log(`Stego CLI\n\nCommands:\n init [--force]\n list-projects [--root <path>]\n new-project --project <project-id> [--title <title>] [--root <path>]\n validate --project <project-id> [--file <project-relative-manuscript-path>] [--root <path>]\n build --project <project-id> [--root <path>]\n check-stage --project <project-id> --stage <draft|revise|line-edit|proof|final> [--file <project-relative-manuscript-path>] [--root <path>]\n export --project <project-id> --format <md|docx|pdf|epub> [--output <path>] [--root <path>]\n`);
|
|
750
|
+
console.log(`Stego CLI\n\nCommands:\n init [--force]\n list-projects [--root <path>]\n new-project --project <project-id> [--title <title>] [--root <path>]\n new --project <project-id> [--i <prefix>|-i <prefix>] [--root <path>]\n validate --project <project-id> [--file <project-relative-manuscript-path>] [--root <path>]\n build --project <project-id> [--root <path>]\n check-stage --project <project-id> --stage <draft|revise|line-edit|proof|final> [--file <project-relative-manuscript-path>] [--root <path>]\n lint --project <project-id> [--manuscript|--spine] [--root <path>]\n export --project <project-id> --format <md|docx|pdf|epub> [--output <path>] [--root <path>]\n`);
|
|
702
751
|
}
|
|
703
752
|
function listProjects() {
|
|
704
753
|
const ids = getProjectIds();
|
|
@@ -729,6 +778,7 @@ async function createProject(projectIdOption, titleOption) {
|
|
|
729
778
|
const notesDir = path.join(projectRoot, config.notesDir);
|
|
730
779
|
fs.mkdirSync(notesDir, { recursive: true });
|
|
731
780
|
fs.mkdirSync(path.join(projectRoot, config.distDir), { recursive: true });
|
|
781
|
+
const manuscriptDir = path.join(projectRoot, config.chapterDir);
|
|
732
782
|
const projectJson = {
|
|
733
783
|
id: projectId,
|
|
734
784
|
title: titleOption?.trim() || toDisplayTitle(projectId),
|
|
@@ -759,6 +809,8 @@ async function createProject(projectIdOption, titleOption) {
|
|
|
759
809
|
name: `stego-project-${projectId}`,
|
|
760
810
|
private: true,
|
|
761
811
|
scripts: {
|
|
812
|
+
new: "npx --no-install stego new",
|
|
813
|
+
lint: "npx --no-install stego lint",
|
|
762
814
|
validate: "npx --no-install stego validate",
|
|
763
815
|
build: "npx --no-install stego build",
|
|
764
816
|
"check-stage": "npx --no-install stego check-stage",
|
|
@@ -767,6 +819,17 @@ async function createProject(projectIdOption, titleOption) {
|
|
|
767
819
|
};
|
|
768
820
|
const projectPackagePath = path.join(projectRoot, "package.json");
|
|
769
821
|
fs.writeFileSync(projectPackagePath, `${JSON.stringify(projectPackage, null, 2)}\n`, "utf8");
|
|
822
|
+
const starterManuscriptPath = path.join(manuscriptDir, "100-hello-world.md");
|
|
823
|
+
fs.writeFileSync(starterManuscriptPath, `---
|
|
824
|
+
status: draft
|
|
825
|
+
chapter: 1
|
|
826
|
+
chapter_title: Hello World
|
|
827
|
+
---
|
|
828
|
+
|
|
829
|
+
# Hello World
|
|
830
|
+
|
|
831
|
+
Start writing here.
|
|
832
|
+
`, "utf8");
|
|
770
833
|
const charactersNotesPath = path.join(spineDir, "characters.md");
|
|
771
834
|
fs.writeFileSync(charactersNotesPath, "# Characters\n\n", "utf8");
|
|
772
835
|
const projectExtensionsPath = path.join(projectRoot, ".vscode", "extensions.json");
|
|
@@ -779,12 +842,103 @@ async function createProject(projectIdOption, titleOption) {
|
|
|
779
842
|
logLine(`Created project: ${path.relative(repoRoot, projectRoot)}`);
|
|
780
843
|
logLine(`- ${path.relative(repoRoot, projectJsonPath)}`);
|
|
781
844
|
logLine(`- ${path.relative(repoRoot, projectPackagePath)}`);
|
|
845
|
+
logLine(`- ${path.relative(repoRoot, starterManuscriptPath)}`);
|
|
782
846
|
logLine(`- ${path.relative(repoRoot, charactersNotesPath)}`);
|
|
783
847
|
logLine(`- ${path.relative(repoRoot, projectExtensionsPath)}`);
|
|
784
848
|
if (projectSettingsPath) {
|
|
785
849
|
logLine(`- ${path.relative(repoRoot, projectSettingsPath)}`);
|
|
786
850
|
}
|
|
787
851
|
}
|
|
852
|
+
function createNewManuscript(project, requestedPrefixRaw) {
|
|
853
|
+
fs.mkdirSync(project.manuscriptDir, { recursive: true });
|
|
854
|
+
const requiredMetadataState = resolveRequiredMetadata(project, config);
|
|
855
|
+
const requiredMetadataErrors = requiredMetadataState.issues
|
|
856
|
+
.filter((issue) => issue.level === "error")
|
|
857
|
+
.map((issue) => issue.message);
|
|
858
|
+
if (requiredMetadataErrors.length > 0) {
|
|
859
|
+
throw new Error(`Unable to resolve required metadata for project '${project.id}': ${requiredMetadataErrors.join(" ")}`);
|
|
860
|
+
}
|
|
861
|
+
const existingEntries = listManuscriptOrderEntries(project.manuscriptDir);
|
|
862
|
+
const explicitPrefix = parseManuscriptPrefix(requestedPrefixRaw);
|
|
863
|
+
const nextPrefix = explicitPrefix ?? inferNextManuscriptPrefix(existingEntries);
|
|
864
|
+
const collision = existingEntries.find((entry) => entry.order === nextPrefix);
|
|
865
|
+
if (collision) {
|
|
866
|
+
throw new Error(`Manuscript prefix '${nextPrefix}' is already used by '${collision.filename}'. Re-run with --i <number> to choose an unused prefix.`);
|
|
867
|
+
}
|
|
868
|
+
const filename = `${nextPrefix}-${DEFAULT_NEW_MANUSCRIPT_SLUG}.md`;
|
|
869
|
+
const manuscriptPath = path.join(project.manuscriptDir, filename);
|
|
870
|
+
const content = renderNewManuscriptTemplate(requiredMetadataState.requiredMetadata);
|
|
871
|
+
fs.writeFileSync(manuscriptPath, content, "utf8");
|
|
872
|
+
return path.relative(repoRoot, manuscriptPath);
|
|
873
|
+
}
|
|
874
|
+
function listManuscriptOrderEntries(manuscriptDir) {
|
|
875
|
+
if (!fs.existsSync(manuscriptDir)) {
|
|
876
|
+
return [];
|
|
877
|
+
}
|
|
878
|
+
return fs
|
|
879
|
+
.readdirSync(manuscriptDir, { withFileTypes: true })
|
|
880
|
+
.filter((entry) => entry.isFile() && entry.name.endsWith(".md"))
|
|
881
|
+
.map((entry) => {
|
|
882
|
+
const match = entry.name.match(/^(\d+)[-_]/);
|
|
883
|
+
if (!match) {
|
|
884
|
+
return null;
|
|
885
|
+
}
|
|
886
|
+
return {
|
|
887
|
+
order: Number(match[1]),
|
|
888
|
+
filename: entry.name
|
|
889
|
+
};
|
|
890
|
+
})
|
|
891
|
+
.filter((entry) => entry !== null)
|
|
892
|
+
.sort((a, b) => {
|
|
893
|
+
if (a.order === b.order) {
|
|
894
|
+
return a.filename.localeCompare(b.filename);
|
|
895
|
+
}
|
|
896
|
+
return a.order - b.order;
|
|
897
|
+
});
|
|
898
|
+
}
|
|
899
|
+
function parseManuscriptPrefix(raw) {
|
|
900
|
+
if (raw == null) {
|
|
901
|
+
return undefined;
|
|
902
|
+
}
|
|
903
|
+
const normalized = raw.trim();
|
|
904
|
+
if (!normalized) {
|
|
905
|
+
throw new Error("Option --i/-i requires a numeric value.");
|
|
906
|
+
}
|
|
907
|
+
if (!/^\d+$/.test(normalized)) {
|
|
908
|
+
throw new Error(`Invalid manuscript prefix '${raw}'. Use a non-negative integer.`);
|
|
909
|
+
}
|
|
910
|
+
const parsed = Number(normalized);
|
|
911
|
+
if (!Number.isSafeInteger(parsed)) {
|
|
912
|
+
throw new Error(`Invalid manuscript prefix '${raw}'. Use a smaller integer value.`);
|
|
913
|
+
}
|
|
914
|
+
return parsed;
|
|
915
|
+
}
|
|
916
|
+
function inferNextManuscriptPrefix(entries) {
|
|
917
|
+
if (entries.length === 0) {
|
|
918
|
+
return 100;
|
|
919
|
+
}
|
|
920
|
+
if (entries.length === 1) {
|
|
921
|
+
return entries[0].order + 100;
|
|
922
|
+
}
|
|
923
|
+
const previous = entries[entries.length - 2].order;
|
|
924
|
+
const latest = entries[entries.length - 1].order;
|
|
925
|
+
const step = latest - previous;
|
|
926
|
+
return latest + (step > 0 ? step : 1);
|
|
927
|
+
}
|
|
928
|
+
function renderNewManuscriptTemplate(requiredMetadata) {
|
|
929
|
+
const lines = ["---", "status: draft"];
|
|
930
|
+
const seenKeys = new Set(["status"]);
|
|
931
|
+
for (const key of requiredMetadata) {
|
|
932
|
+
const normalized = key.trim();
|
|
933
|
+
if (!normalized || seenKeys.has(normalized)) {
|
|
934
|
+
continue;
|
|
935
|
+
}
|
|
936
|
+
seenKeys.add(normalized);
|
|
937
|
+
lines.push(`${normalized}:`);
|
|
938
|
+
}
|
|
939
|
+
lines.push("---", "", "# New Document", "");
|
|
940
|
+
return `${lines.join("\n")}\n`;
|
|
941
|
+
}
|
|
788
942
|
function getProjectIds() {
|
|
789
943
|
const projectsDir = path.join(repoRoot, config.projectsDir);
|
|
790
944
|
if (!fs.existsSync(projectsDir)) {
|
|
@@ -1602,10 +1756,10 @@ function runStageCheck(project, runtimeConfig, stage, onlyFile) {
|
|
|
1602
1756
|
const chapterPaths = report.chapters.map((chapter) => chapter.path);
|
|
1603
1757
|
const spineWords = collectSpineWordsForSpellcheck(report.spineState.ids);
|
|
1604
1758
|
if (policy.enforceMarkdownlint) {
|
|
1605
|
-
issues.push(...runMarkdownlint(project, chapterPaths, true));
|
|
1759
|
+
issues.push(...runMarkdownlint(project, chapterPaths, true, "manuscript"));
|
|
1606
1760
|
}
|
|
1607
1761
|
else {
|
|
1608
|
-
issues.push(...runMarkdownlint(project, chapterPaths, false));
|
|
1762
|
+
issues.push(...runMarkdownlint(project, chapterPaths, false, "manuscript"));
|
|
1609
1763
|
}
|
|
1610
1764
|
if (policy.enforceCSpell) {
|
|
1611
1765
|
issues.push(...runCSpell(chapterPaths, true, spineWords));
|
|
@@ -1615,20 +1769,133 @@ function runStageCheck(project, runtimeConfig, stage, onlyFile) {
|
|
|
1615
1769
|
}
|
|
1616
1770
|
return { chapters: report.chapters, issues };
|
|
1617
1771
|
}
|
|
1618
|
-
function
|
|
1772
|
+
function resolveLintSelection(options) {
|
|
1773
|
+
const manuscript = readBooleanOption(options, "manuscript");
|
|
1774
|
+
const spine = readBooleanOption(options, "spine");
|
|
1775
|
+
if (!manuscript && !spine) {
|
|
1776
|
+
return { manuscript: true, spine: true };
|
|
1777
|
+
}
|
|
1778
|
+
return { manuscript, spine };
|
|
1779
|
+
}
|
|
1780
|
+
function formatLintSelection(selection) {
|
|
1781
|
+
if (selection.manuscript && selection.spine) {
|
|
1782
|
+
return "manuscript + spine";
|
|
1783
|
+
}
|
|
1784
|
+
if (selection.manuscript) {
|
|
1785
|
+
return "manuscript";
|
|
1786
|
+
}
|
|
1787
|
+
if (selection.spine) {
|
|
1788
|
+
return "spine";
|
|
1789
|
+
}
|
|
1790
|
+
return "none";
|
|
1791
|
+
}
|
|
1792
|
+
function runProjectLint(project, selection) {
|
|
1793
|
+
const issues = [];
|
|
1794
|
+
let fileCount = 0;
|
|
1795
|
+
if (selection.manuscript) {
|
|
1796
|
+
const manuscriptFiles = collectTopLevelMarkdownFiles(project.manuscriptDir);
|
|
1797
|
+
if (manuscriptFiles.length === 0) {
|
|
1798
|
+
issues.push(makeIssue("error", "lint", `No manuscript markdown files found in ${project.manuscriptDir}`));
|
|
1799
|
+
}
|
|
1800
|
+
else {
|
|
1801
|
+
fileCount += manuscriptFiles.length;
|
|
1802
|
+
issues.push(...runMarkdownlint(project, manuscriptFiles, true, "manuscript"));
|
|
1803
|
+
}
|
|
1804
|
+
}
|
|
1805
|
+
if (selection.spine) {
|
|
1806
|
+
const spineLintState = collectSpineLintMarkdownFiles(project);
|
|
1807
|
+
issues.push(...spineLintState.issues);
|
|
1808
|
+
if (spineLintState.files.length > 0) {
|
|
1809
|
+
fileCount += spineLintState.files.length;
|
|
1810
|
+
issues.push(...runMarkdownlint(project, spineLintState.files, true, "default"));
|
|
1811
|
+
}
|
|
1812
|
+
}
|
|
1813
|
+
if (fileCount === 0 && issues.length === 0) {
|
|
1814
|
+
issues.push(makeIssue("error", "lint", `No markdown files found for lint scope '${formatLintSelection(selection)}' in project '${project.id}'.`));
|
|
1815
|
+
}
|
|
1816
|
+
return { issues, fileCount };
|
|
1817
|
+
}
|
|
1818
|
+
function collectSpineLintMarkdownFiles(project) {
|
|
1819
|
+
const issues = [];
|
|
1820
|
+
const files = new Set();
|
|
1821
|
+
addMarkdownFilesFromDirectory(files, project.spineDir, true);
|
|
1822
|
+
if (!fs.existsSync(project.spineDir)) {
|
|
1823
|
+
issues.push(makeIssue("warning", "lint", `Missing spine directory: ${project.spineDir}`));
|
|
1824
|
+
}
|
|
1825
|
+
addMarkdownFilesFromDirectory(files, project.notesDir, true);
|
|
1826
|
+
if (!fs.existsSync(project.notesDir)) {
|
|
1827
|
+
issues.push(makeIssue("warning", "lint", `Missing notes directory: ${project.notesDir}`));
|
|
1828
|
+
}
|
|
1829
|
+
for (const file of collectTopLevelMarkdownFiles(project.root)) {
|
|
1830
|
+
files.add(file);
|
|
1831
|
+
}
|
|
1832
|
+
const sortedFiles = Array.from(files).sort();
|
|
1833
|
+
if (sortedFiles.length === 0) {
|
|
1834
|
+
issues.push(makeIssue("error", "lint", `No spine/notes markdown files found in ${project.spineDir}, ${project.notesDir}, or project root.`));
|
|
1835
|
+
}
|
|
1836
|
+
return { files: sortedFiles, issues };
|
|
1837
|
+
}
|
|
1838
|
+
function collectTopLevelMarkdownFiles(directory) {
|
|
1839
|
+
if (!fs.existsSync(directory) || !fs.statSync(directory).isDirectory()) {
|
|
1840
|
+
return [];
|
|
1841
|
+
}
|
|
1842
|
+
return fs
|
|
1843
|
+
.readdirSync(directory, { withFileTypes: true })
|
|
1844
|
+
.filter((entry) => entry.isFile() && entry.name.endsWith(".md"))
|
|
1845
|
+
.map((entry) => path.join(directory, entry.name))
|
|
1846
|
+
.sort();
|
|
1847
|
+
}
|
|
1848
|
+
function addMarkdownFilesFromDirectory(target, directory, recursive) {
|
|
1849
|
+
if (!fs.existsSync(directory) || !fs.statSync(directory).isDirectory()) {
|
|
1850
|
+
return;
|
|
1851
|
+
}
|
|
1852
|
+
const stack = [directory];
|
|
1853
|
+
while (stack.length > 0) {
|
|
1854
|
+
const current = stack.pop();
|
|
1855
|
+
if (!current) {
|
|
1856
|
+
continue;
|
|
1857
|
+
}
|
|
1858
|
+
const entries = fs.readdirSync(current, { withFileTypes: true }).sort((a, b) => a.name.localeCompare(b.name));
|
|
1859
|
+
for (const entry of entries) {
|
|
1860
|
+
const fullPath = path.join(current, entry.name);
|
|
1861
|
+
if (entry.isFile() && entry.name.endsWith(".md")) {
|
|
1862
|
+
target.add(fullPath);
|
|
1863
|
+
continue;
|
|
1864
|
+
}
|
|
1865
|
+
if (recursive && entry.isDirectory()) {
|
|
1866
|
+
stack.push(fullPath);
|
|
1867
|
+
}
|
|
1868
|
+
}
|
|
1869
|
+
}
|
|
1870
|
+
}
|
|
1871
|
+
function runMarkdownlint(project, files, required, profile = "default") {
|
|
1872
|
+
if (files.length === 0) {
|
|
1873
|
+
return [];
|
|
1874
|
+
}
|
|
1619
1875
|
const markdownlintCommand = resolveCommand("markdownlint");
|
|
1620
1876
|
if (!markdownlintCommand) {
|
|
1621
1877
|
if (required) {
|
|
1622
1878
|
return [
|
|
1623
|
-
makeIssue("error", "tooling", "markdownlint is required for this
|
|
1879
|
+
makeIssue("error", "tooling", "markdownlint is required for this command but not installed. Run 'npm i' in the repo root.")
|
|
1624
1880
|
];
|
|
1625
1881
|
}
|
|
1626
1882
|
return [];
|
|
1627
1883
|
}
|
|
1628
|
-
const
|
|
1629
|
-
const
|
|
1630
|
-
|
|
1631
|
-
|
|
1884
|
+
const manuscriptProjectConfigPath = path.join(project.root, ".markdownlint.manuscript.json");
|
|
1885
|
+
const manuscriptRepoConfigPath = path.join(repoRoot, ".markdownlint.manuscript.json");
|
|
1886
|
+
const defaultProjectConfigPath = path.join(project.root, ".markdownlint.json");
|
|
1887
|
+
const defaultRepoConfigPath = path.join(repoRoot, ".markdownlint.json");
|
|
1888
|
+
const markdownlintConfigPath = profile === "manuscript"
|
|
1889
|
+
? (fs.existsSync(manuscriptProjectConfigPath)
|
|
1890
|
+
? manuscriptProjectConfigPath
|
|
1891
|
+
: fs.existsSync(manuscriptRepoConfigPath)
|
|
1892
|
+
? manuscriptRepoConfigPath
|
|
1893
|
+
: fs.existsSync(defaultProjectConfigPath)
|
|
1894
|
+
? defaultProjectConfigPath
|
|
1895
|
+
: defaultRepoConfigPath)
|
|
1896
|
+
: (fs.existsSync(defaultProjectConfigPath)
|
|
1897
|
+
? defaultProjectConfigPath
|
|
1898
|
+
: defaultRepoConfigPath);
|
|
1632
1899
|
const prepared = prepareFilesWithoutComments(files);
|
|
1633
1900
|
try {
|
|
1634
1901
|
const result = spawnSync(markdownlintCommand, ["--config", markdownlintConfigPath, ...prepared.files], {
|
package/package.json
CHANGED
|
@@ -1,17 +1,17 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "stego-cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Installable CLI for the Stego writing monorepo workflow.",
|
|
6
6
|
"license": "Apache-2.0",
|
|
7
7
|
"repository": {
|
|
8
8
|
"type": "git",
|
|
9
|
-
"url": "https://github.com/matt-gold/stego.git"
|
|
9
|
+
"url": "https://github.com/matt-gold/stego-cli.git"
|
|
10
10
|
},
|
|
11
11
|
"bugs": {
|
|
12
|
-
"url": "https://github.com/matt-gold/stego/issues"
|
|
12
|
+
"url": "https://github.com/matt-gold/stego-cli/issues"
|
|
13
13
|
},
|
|
14
|
-
"homepage": "https://github.com/matt-gold/stego#readme",
|
|
14
|
+
"homepage": "https://github.com/matt-gold/stego-cli#readme",
|
|
15
15
|
"bin": {
|
|
16
16
|
"stego": "dist/stego-cli.js"
|
|
17
17
|
},
|
|
@@ -28,6 +28,7 @@
|
|
|
28
28
|
".vscode/extensions.json",
|
|
29
29
|
".gitignore",
|
|
30
30
|
".markdownlint.json",
|
|
31
|
+
".markdownlint.manuscript.json",
|
|
31
32
|
".cspell.json",
|
|
32
33
|
"stego.config.json",
|
|
33
34
|
"README.md"
|
|
@@ -41,6 +42,8 @@
|
|
|
41
42
|
"release:version": "changeset version",
|
|
42
43
|
"list-projects": "node --experimental-strip-types tools/stego-cli.ts list-projects",
|
|
43
44
|
"new-project": "node --experimental-strip-types tools/stego-cli.ts new-project",
|
|
45
|
+
"new": "node --experimental-strip-types tools/stego-cli.ts new",
|
|
46
|
+
"lint": "node --experimental-strip-types tools/stego-cli.ts lint",
|
|
44
47
|
"validate": "node --experimental-strip-types tools/stego-cli.ts validate",
|
|
45
48
|
"build": "node --experimental-strip-types tools/stego-cli.ts build",
|
|
46
49
|
"check-stage": "node --experimental-strip-types tools/stego-cli.ts check-stage",
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
"name": "stego-project-fiction-example",
|
|
3
3
|
"private": true,
|
|
4
4
|
"scripts": {
|
|
5
|
+
"new": "node --experimental-strip-types ../../tools/stego-cli.ts new",
|
|
5
6
|
"validate": "node --experimental-strip-types ../../tools/stego-cli.ts validate",
|
|
6
7
|
"build": "node --experimental-strip-types ../../tools/stego-cli.ts build",
|
|
7
8
|
"check-stage": "node --experimental-strip-types ../../tools/stego-cli.ts check-stage",
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
# Characters
|
|
2
2
|
|
|
3
3
|
## CHAR-MATTHAEUS
|
|
4
|
+
label: Magister Matthaeus de Rota
|
|
4
5
|
|
|
5
6
|
- Magister Matthaeus de Rota
|
|
6
7
|
- Role: Scholar of medicine and astrology at the University of Paris
|
|
@@ -9,6 +10,7 @@
|
|
|
9
10
|
- Arc: Builds a total explanation of the {{pestilence}} and dies at peace inside it; the question is whether his peace is understanding or its most sophisticated substitute
|
|
10
11
|
|
|
11
12
|
## CHAR-ETIENNE
|
|
13
|
+
label: Etienne of Saint-Marcel
|
|
12
14
|
|
|
13
15
|
- Etienne of Saint-Marcel
|
|
14
16
|
- Role: Young cleric-scribe attached to Matthaeus (CHAR-MATTHAEUS)
|
|
@@ -16,6 +18,7 @@
|
|
|
16
18
|
- Function: The story's witness; records the system without fully believing it, but also without offering an alternative
|
|
17
19
|
|
|
18
20
|
## CHAR-AGNES
|
|
21
|
+
label: Agnes the apothecary
|
|
19
22
|
|
|
20
23
|
- Agnes the apothecary
|
|
21
24
|
- Role: Compounder and practical healer near the Petit Pont; supplies Hôtel-Dieu (LOC-HOTELDIEU)
|
|
@@ -24,6 +27,7 @@
|
|
|
24
27
|
- Function: The counterweight; asks whether a system that can absorb any evidence without changing is a system or a habit
|
|
25
28
|
|
|
26
29
|
## CHAR-RAOUL
|
|
30
|
+
label: Canon Raoul de Villiers
|
|
27
31
|
|
|
28
32
|
- Canon Raoul de Villiers
|
|
29
33
|
- Role: Cathedral canon and royal intermediary overseeing the inquiry
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
# Locations
|
|
2
2
|
|
|
3
3
|
## LOC-COLLEGE
|
|
4
|
+
label: College chamber near the Rue Saint-Jacques
|
|
4
5
|
|
|
5
6
|
- College chamber near the Rue Saint-Jacques
|
|
6
7
|
- Study and disputation room
|
|
@@ -9,6 +10,7 @@
|
|
|
9
10
|
- Significance: The space where the system is built; physically separated from the wards and streets where the plague actually operates
|
|
10
11
|
|
|
11
12
|
## LOC-HOTELDIEU
|
|
13
|
+
label: "Hôtel-Dieu"
|
|
12
14
|
|
|
13
15
|
- Hôtel-Dieu
|
|
14
16
|
- Hospital ward near Notre-Dame
|
|
@@ -17,6 +19,7 @@
|
|
|
17
19
|
- Significance: Where data is collected; the distance between this room and the college chamber is the distance between observation and explanation
|
|
18
20
|
|
|
19
21
|
## LOC-QUAY
|
|
22
|
+
label: Grain quay on the Seine
|
|
20
23
|
|
|
21
24
|
- Grain quay on the Seine
|
|
22
25
|
- River unloading zone
|
|
@@ -25,6 +28,7 @@
|
|
|
25
28
|
- Significance: Agnes's observations (SRC-WARD-DATA) trace infection along this route; it is the strongest evidence for material transmission and the hardest for the celestial framework (SRC-CONJUNCTION) to accommodate
|
|
26
29
|
|
|
27
30
|
## LOC-CHARNEL
|
|
31
|
+
label: Charnel precinct at the cemetery edge
|
|
28
32
|
|
|
29
33
|
- Charnel precinct at the cemetery edge
|
|
30
34
|
- Overflow burial ground
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
# Sources
|
|
2
2
|
|
|
3
3
|
## SRC-CONJUNCTION
|
|
4
|
+
label: The Great Conjunction theory
|
|
4
5
|
|
|
5
6
|
- The Great Conjunction theory
|
|
6
7
|
- Tradition: University astrology ([Paris faculty opinion of 1348](https://en.wikipedia.org/wiki/Black_Death#Medical_knowledge))
|
|
@@ -10,6 +11,7 @@
|
|
|
10
11
|
- Limitation: Explains everything at once, which means it predicts nothing in particular
|
|
11
12
|
|
|
12
13
|
## SRC-GALEN
|
|
14
|
+
label: Galenic humoral medicine
|
|
13
15
|
|
|
14
16
|
- Galenic humoral medicine
|
|
15
17
|
- Tradition: Greco-Arabic medical inheritance
|
|
@@ -19,6 +21,7 @@
|
|
|
19
21
|
- Limitation: Cannot explain why entire neighborhoods fall at once regardless of individual constitution
|
|
20
22
|
|
|
21
23
|
## SRC-WARD-DATA
|
|
24
|
+
label: "Agnes's ward observations"
|
|
22
25
|
|
|
23
26
|
- Agnes's ward observations
|
|
24
27
|
- Tradition: None; empirical record-keeping without institutional backing
|
|
@@ -10,6 +10,7 @@ concepts:
|
|
|
10
10
|
commands:
|
|
11
11
|
- CMD-LIST-PROJECTS
|
|
12
12
|
- CMD-NEW-PROJECT
|
|
13
|
+
- CMD-NEW
|
|
13
14
|
- CMD-VALIDATE
|
|
14
15
|
- CMD-BUILD
|
|
15
16
|
- CMD-CHECK-STAGE
|
|
@@ -41,6 +42,7 @@ From the workspace root, target a project with `--project`.
|
|
|
41
42
|
|
|
42
43
|
```bash
|
|
43
44
|
stego list-projects
|
|
45
|
+
stego new --project fiction-example
|
|
44
46
|
stego validate --project fiction-example
|
|
45
47
|
stego build --project fiction-example
|
|
46
48
|
stego check-stage --project fiction-example --stage revise
|
|
@@ -53,6 +55,7 @@ Projects also include local npm scripts. These are useful when you want to stay
|
|
|
53
55
|
|
|
54
56
|
```bash
|
|
55
57
|
cd projects/fiction-example
|
|
58
|
+
npm run new
|
|
56
59
|
npm run validate
|
|
57
60
|
npm run build
|
|
58
61
|
npm run check-stage -- --stage revise
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
"name": "stego-project-stego-docs",
|
|
3
3
|
"private": true,
|
|
4
4
|
"scripts": {
|
|
5
|
+
"new": "node --experimental-strip-types ../../tools/stego-cli.ts new",
|
|
5
6
|
"validate": "node --experimental-strip-types ../../tools/stego-cli.ts validate",
|
|
6
7
|
"build": "node --experimental-strip-types ../../tools/stego-cli.ts build",
|
|
7
8
|
"check-stage": "node --experimental-strip-types ../../tools/stego-cli.ts check-stage",
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
# Commands
|
|
2
2
|
|
|
3
3
|
## CMD-INIT
|
|
4
|
+
label: stego init [--force]
|
|
4
5
|
|
|
5
6
|
- `stego init [--force]`
|
|
6
7
|
- Initialize a Stego workspace in the current directory.
|
|
@@ -9,6 +10,7 @@
|
|
|
9
10
|
- Related integrations: INT-VSCODE.
|
|
10
11
|
|
|
11
12
|
## CMD-LIST-PROJECTS
|
|
13
|
+
label: stego list-projects [--root <path>]
|
|
12
14
|
|
|
13
15
|
- `stego list-projects [--root <path>]`
|
|
14
16
|
- List projects found in the current workspace.
|
|
@@ -16,13 +18,24 @@
|
|
|
16
18
|
- Related concepts: CON-WORKSPACE, CON-PROJECT.
|
|
17
19
|
|
|
18
20
|
## CMD-NEW-PROJECT
|
|
21
|
+
label: stego new-project --project <project-id> [--title <title>] [--root <path>]
|
|
19
22
|
|
|
20
23
|
- `stego new-project --project <project-id> [--title <title>] [--root <path>]`
|
|
21
24
|
- Scaffold a new project under `projects/`.
|
|
22
25
|
- Related workflows: FLOW-NEW-PROJECT.
|
|
23
26
|
- Related concepts: CON-PROJECT, CON-MANUSCRIPT, CON-NOTES, CON-DIST.
|
|
24
27
|
|
|
28
|
+
## CMD-NEW
|
|
29
|
+
label: stego new --project <project-id> [--i <prefix>|-i <prefix>] [--root <path>]
|
|
30
|
+
|
|
31
|
+
- `stego new --project <project-id> [--i <prefix>|-i <prefix>] [--root <path>]`
|
|
32
|
+
- Create a new manuscript file with an inferred numeric prefix and draft frontmatter.
|
|
33
|
+
- Related workflows: FLOW-DAILY-WRITING.
|
|
34
|
+
- Related concepts: CON-MANUSCRIPT, CON-METADATA.
|
|
35
|
+
- Related configuration: CFG-REQUIRED-METADATA.
|
|
36
|
+
|
|
25
37
|
## CMD-VALIDATE
|
|
38
|
+
label: stego validate --project <project-id> [--file <project-relative-manuscript-path>] [--root <path>]
|
|
26
39
|
|
|
27
40
|
- `stego validate --project <project-id> [--file <project-relative-manuscript-path>] [--root <path>]`
|
|
28
41
|
- Validate project configuration, manuscript structure, metadata, and references.
|
|
@@ -31,6 +44,7 @@
|
|
|
31
44
|
- Related configuration: CFG-REQUIRED-METADATA, CFG-SPINE-CATEGORIES.
|
|
32
45
|
|
|
33
46
|
## CMD-BUILD
|
|
47
|
+
label: stego build --project <project-id> [--root <path>]
|
|
34
48
|
|
|
35
49
|
- `stego build --project <project-id> [--root <path>]`
|
|
36
50
|
- Compile manuscript files into one generated markdown output.
|
|
@@ -39,6 +53,7 @@
|
|
|
39
53
|
- Related configuration: CFG-COMPILE-STRUCTURE, CFG-COMPILE-LEVELS.
|
|
40
54
|
|
|
41
55
|
## CMD-CHECK-STAGE
|
|
56
|
+
label: stego check-stage --project <project-id> --stage <draft|revise|line-edit|proof|final> [--file <project-relative-manuscript-path>] [--root <path>]
|
|
42
57
|
|
|
43
58
|
- `stego check-stage --project <project-id> --stage <draft|revise|line-edit|proof|final> [--file <project-relative-manuscript-path>] [--root <path>]`
|
|
44
59
|
- Run stage-aware checks for a requested editorial stage.
|
|
@@ -47,6 +62,7 @@
|
|
|
47
62
|
- Related configuration: CFG-STAGE-POLICIES, CFG-ALLOWED-STATUSES.
|
|
48
63
|
|
|
49
64
|
## CMD-EXPORT
|
|
65
|
+
label: stego export --project <project-id> --format <md|docx|pdf|epub> [--output <path>] [--root <path>]
|
|
50
66
|
|
|
51
67
|
- `stego export --project <project-id> --format <md|docx|pdf|epub> [--output <path>] [--root <path>]`
|
|
52
68
|
- Export compiled output to target formats.
|
|
@@ -1,48 +1,56 @@
|
|
|
1
1
|
# Concepts
|
|
2
2
|
|
|
3
3
|
## CON-WORKSPACE
|
|
4
|
+
label: A Stego workspace is the root directory containing `stego.config.json` and `projects/`.
|
|
4
5
|
|
|
5
6
|
- A Stego workspace is the root directory containing `stego.config.json` and `projects/`.
|
|
6
7
|
- Related commands: CMD-INIT, CMD-LIST-PROJECTS.
|
|
7
8
|
- Related workflows: FLOW-INIT-WORKSPACE.
|
|
8
9
|
|
|
9
10
|
## CON-PROJECT
|
|
11
|
+
label: A project is one writing unit inside `projects/<project-id>/` with its own `stego-project.json` and manuscript files in `/projects/<project-id>/manuscripts`.
|
|
10
12
|
|
|
11
13
|
- A project is one writing unit inside `projects/<project-id>/` with its own `stego-project.json` and manuscript files in `/projects/<project-id>/manuscripts`.
|
|
12
14
|
- Related commands: CMD-NEW-PROJECT, CMD-VALIDATE, CMD-BUILD.
|
|
13
15
|
- Related workflows: FLOW-NEW-PROJECT, FLOW-DAILY-WRITING.
|
|
14
16
|
|
|
15
17
|
## CON-MANUSCRIPT
|
|
18
|
+
label: `manuscript/` contains canonical source writing files ordered by filename prefix.
|
|
16
19
|
|
|
17
20
|
- `manuscript/` contains canonical source writing files ordered by filename prefix.
|
|
18
21
|
- Related commands: CMD-VALIDATE, CMD-BUILD.
|
|
19
22
|
- Related configuration: CFG-REQUIRED-METADATA, CFG-COMPILE-STRUCTURE.
|
|
20
23
|
|
|
21
24
|
## CON-SPINE
|
|
25
|
+
label: `spine/` stores canonical entities used for continuity and navigation.
|
|
22
26
|
|
|
23
27
|
- `spine/` stores canonical entities used for continuity and navigation.
|
|
24
28
|
- Related configuration: CFG-SPINE-CATEGORIES.
|
|
25
29
|
- Related integrations: INT-STEGO-EXTENSION.
|
|
26
30
|
|
|
27
31
|
## CON-NOTES
|
|
32
|
+
label: `notes/` contains supporting material that is not part of compiled manuscript output.
|
|
28
33
|
|
|
29
34
|
- `notes/` contains supporting material that is not part of compiled manuscript output.
|
|
30
35
|
- Related commands: CMD-NEW-PROJECT.
|
|
31
36
|
- Related workflows: FLOW-DAILY-WRITING.
|
|
32
37
|
|
|
33
38
|
## CON-DIST
|
|
39
|
+
label: `dist/` is generated output only and can be rebuilt from sources.
|
|
34
40
|
|
|
35
41
|
- `dist/` is generated output only and can be rebuilt from sources.
|
|
36
42
|
- Related commands: CMD-BUILD, CMD-EXPORT.
|
|
37
43
|
- Related workflows: FLOW-BUILD-EXPORT, FLOW-PROOF-RELEASE.
|
|
38
44
|
|
|
39
45
|
## CON-METADATA
|
|
46
|
+
label: "Frontmatter metadata drives validation, stage checks, grouping, and continuity references."
|
|
40
47
|
|
|
41
48
|
- Frontmatter metadata drives validation, stage checks, grouping, and continuity references.
|
|
42
49
|
- Related commands: CMD-VALIDATE, CMD-CHECK-STAGE.
|
|
43
50
|
- Related configuration: CFG-REQUIRED-METADATA, CFG-ALLOWED-STATUSES.
|
|
44
51
|
|
|
45
52
|
## CON-STAGE-GATE
|
|
53
|
+
label: Stage gates apply stricter checks as work moves from drafting to release.
|
|
46
54
|
|
|
47
55
|
- Stage gates apply stricter checks as work moves from drafting to release.
|
|
48
56
|
- Related commands: CMD-CHECK-STAGE.
|
|
@@ -50,12 +58,14 @@
|
|
|
50
58
|
- Related configuration: CFG-STAGE-POLICIES.
|
|
51
59
|
|
|
52
60
|
## CON-COMPILE-STRUCTURE
|
|
61
|
+
label: Compile structure groups ordered files into larger sections during build.
|
|
53
62
|
|
|
54
63
|
- Compile structure groups ordered files into larger sections during build.
|
|
55
64
|
- Related commands: CMD-BUILD.
|
|
56
65
|
- Related configuration: CFG-COMPILE-STRUCTURE, CFG-COMPILE-LEVELS.
|
|
57
66
|
|
|
58
67
|
## CON-SPINE-CATEGORY
|
|
68
|
+
label: "A spine category defines a metadata key, ID prefix, and canonical notes file."
|
|
59
69
|
|
|
60
70
|
- A spine category defines a metadata key, ID prefix, and canonical notes file.
|
|
61
71
|
- Related concepts: CON-SPINE, CON-METADATA.
|
|
@@ -1,48 +1,56 @@
|
|
|
1
1
|
# Configuration
|
|
2
2
|
|
|
3
3
|
## CFG-STEGO-CONFIG
|
|
4
|
+
label: Workspace-level configuration in `stego.config.json` defines shared directories and stage policies.
|
|
4
5
|
|
|
5
6
|
- Workspace-level configuration in `stego.config.json` defines shared directories and stage policies.
|
|
6
7
|
- Related concepts: CON-WORKSPACE.
|
|
7
8
|
- Related commands: CMD-LIST-PROJECTS, CMD-CHECK-STAGE.
|
|
8
9
|
|
|
9
10
|
## CFG-STEGO-PROJECT
|
|
11
|
+
label: "Project-level configuration in `stego-project.json` defines metadata rules, grouping, and spine categories."
|
|
10
12
|
|
|
11
13
|
- Project-level configuration in `stego-project.json` defines metadata rules, grouping, and spine categories.
|
|
12
14
|
- Related concepts: CON-PROJECT, CON-METADATA, CON-SPINE.
|
|
13
15
|
- Related commands: CMD-VALIDATE, CMD-BUILD.
|
|
14
16
|
|
|
15
17
|
## CFG-REQUIRED-METADATA
|
|
18
|
+
label: Advisory list of frontmatter keys expected in manuscript files.
|
|
16
19
|
|
|
17
20
|
- Advisory list of frontmatter keys expected in manuscript files.
|
|
18
21
|
- Related concepts: CON-METADATA.
|
|
19
22
|
- Related commands: CMD-VALIDATE.
|
|
20
23
|
|
|
21
24
|
## CFG-COMPILE-STRUCTURE
|
|
25
|
+
label: Build grouping configuration that defines structural levels and heading behavior.
|
|
22
26
|
|
|
23
27
|
- Build grouping configuration that defines structural levels and heading behavior.
|
|
24
28
|
- Related concepts: CON-COMPILE-STRUCTURE.
|
|
25
29
|
- Related commands: CMD-BUILD.
|
|
26
30
|
|
|
27
31
|
## CFG-COMPILE-LEVELS
|
|
32
|
+
label: "The ordered `levels` array inside compile structure, with keys, labels, title keys, and page break options."
|
|
28
33
|
|
|
29
34
|
- The ordered `levels` array inside compile structure, with keys, labels, title keys, and page break options.
|
|
30
35
|
- Related configuration: CFG-COMPILE-STRUCTURE.
|
|
31
36
|
- Related concepts: CON-COMPILE-STRUCTURE.
|
|
32
37
|
|
|
33
38
|
## CFG-SPINE-CATEGORIES
|
|
39
|
+
label: Per-project category definitions mapping metadata keys to ID prefixes and spine files.
|
|
34
40
|
|
|
35
41
|
- Per-project category definitions mapping metadata keys to ID prefixes and spine files.
|
|
36
42
|
- Related concepts: CON-SPINE, CON-SPINE-CATEGORY.
|
|
37
43
|
- Related commands: CMD-VALIDATE.
|
|
38
44
|
|
|
39
45
|
## CFG-STAGE-POLICIES
|
|
46
|
+
label: Stage policy settings determine which checks are enforced at each stage.
|
|
40
47
|
|
|
41
48
|
- Stage policy settings determine which checks are enforced at each stage.
|
|
42
49
|
- Related concepts: CON-STAGE-GATE.
|
|
43
50
|
- Related commands: CMD-CHECK-STAGE.
|
|
44
51
|
|
|
45
52
|
## CFG-ALLOWED-STATUSES
|
|
53
|
+
label: Workspace-level list of allowed manuscript statuses.
|
|
46
54
|
|
|
47
55
|
- Workspace-level list of allowed manuscript statuses.
|
|
48
56
|
- Related concepts: CON-METADATA, CON-STAGE-GATE.
|
|
@@ -1,36 +1,42 @@
|
|
|
1
1
|
# Integrations
|
|
2
2
|
|
|
3
3
|
## INT-VSCODE
|
|
4
|
+
label: VS Code is the primary editor environment for Stego projects.
|
|
4
5
|
|
|
5
6
|
- VS Code is the primary editor environment for Stego projects.
|
|
6
7
|
- Related workflows: FLOW-INIT-WORKSPACE, FLOW-DAILY-WRITING.
|
|
7
8
|
- Related commands: CMD-INIT.
|
|
8
9
|
|
|
9
10
|
## INT-STEGO-EXTENSION
|
|
11
|
+
label: "The Stego VS Code extension is the official UI for Stego projects, including status controls, checks, and Spine Browser navigation."
|
|
10
12
|
|
|
11
13
|
- The Stego VS Code extension is the official UI for Stego projects, including status controls, checks, and Spine Browser navigation.
|
|
12
14
|
- Related concepts: CON-SPINE, CON-STAGE-GATE.
|
|
13
15
|
- Related workflows: FLOW-DAILY-WRITING, FLOW-STAGE-PROMOTION.
|
|
14
16
|
|
|
15
17
|
## INT-SAURUS-EXTENSION
|
|
18
|
+
label: The Saurus extension complements prose editing and research workflows in project folders.
|
|
16
19
|
|
|
17
20
|
- The Saurus extension complements prose editing and research workflows in project folders.
|
|
18
21
|
- Related integrations: INT-VSCODE.
|
|
19
22
|
- Related workflows: FLOW-DAILY-WRITING.
|
|
20
23
|
|
|
21
24
|
## INT-PANDOC
|
|
25
|
+
label: "Pandoc is used for optional export formats such as docx, pdf, and epub."
|
|
22
26
|
|
|
23
27
|
- Pandoc is used for optional export formats such as docx, pdf, and epub.
|
|
24
28
|
- Related commands: CMD-EXPORT.
|
|
25
29
|
- Related workflows: FLOW-BUILD-EXPORT.
|
|
26
30
|
|
|
27
31
|
## INT-MARKDOWNLINT
|
|
32
|
+
label: Markdownlint is used in stricter proofreading and release stages.
|
|
28
33
|
|
|
29
34
|
- Markdownlint is used in stricter proofreading and release stages.
|
|
30
35
|
- Related concepts: CON-STAGE-GATE.
|
|
31
36
|
- Related workflows: FLOW-PROOF-RELEASE.
|
|
32
37
|
|
|
33
38
|
## INT-CSPELL
|
|
39
|
+
label: CSpell supports spelling and terminology checks during later-stage quality passes.
|
|
34
40
|
|
|
35
41
|
- CSpell supports spelling and terminology checks during later-stage quality passes.
|
|
36
42
|
- Related concepts: CON-STAGE-GATE.
|
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
# Workflows
|
|
2
2
|
|
|
3
3
|
## FLOW-INIT-WORKSPACE
|
|
4
|
+
label: "Install the CLI, initialize a workspace, install local dev tools, and inspect scaffolded projects."
|
|
4
5
|
|
|
5
6
|
- Install the CLI, initialize a workspace, install local dev tools, and inspect scaffolded projects.
|
|
6
7
|
- Related commands: CMD-INIT, CMD-LIST-PROJECTS.
|
|
7
8
|
- Related concepts: CON-WORKSPACE, CON-PROJECT.
|
|
8
9
|
|
|
9
10
|
## FLOW-DAILY-WRITING
|
|
11
|
+
label: "Open one project, write in manuscript files, validate, build, and commit progress."
|
|
10
12
|
|
|
11
13
|
- Open one project, write in manuscript files, validate, build, and commit progress.
|
|
12
14
|
- Related commands: CMD-VALIDATE, CMD-BUILD.
|
|
@@ -14,6 +16,7 @@
|
|
|
14
16
|
- Related integrations: INT-VSCODE.
|
|
15
17
|
|
|
16
18
|
## FLOW-NEW-PROJECT
|
|
19
|
+
label: "Create a new project, review generated folders, and configure project metadata rules."
|
|
17
20
|
|
|
18
21
|
- Create a new project, review generated folders, and configure project metadata rules.
|
|
19
22
|
- Related commands: CMD-NEW-PROJECT, CMD-VALIDATE.
|
|
@@ -21,6 +24,7 @@
|
|
|
21
24
|
- Related configuration: CFG-STEGO-PROJECT.
|
|
22
25
|
|
|
23
26
|
## FLOW-STAGE-PROMOTION
|
|
27
|
+
label: Move files through statuses and verify readiness with stage checks.
|
|
24
28
|
|
|
25
29
|
- Move files through statuses and verify readiness with stage checks.
|
|
26
30
|
- Related commands: CMD-CHECK-STAGE, CMD-VALIDATE.
|
|
@@ -28,6 +32,7 @@
|
|
|
28
32
|
- Related configuration: CFG-STAGE-POLICIES, CFG-ALLOWED-STATUSES.
|
|
29
33
|
|
|
30
34
|
## FLOW-BUILD-EXPORT
|
|
35
|
+
label: Build a compiled markdown manuscript and export distribution formats.
|
|
31
36
|
|
|
32
37
|
- Build a compiled markdown manuscript and export distribution formats.
|
|
33
38
|
- Related commands: CMD-BUILD, CMD-EXPORT.
|
|
@@ -35,6 +40,7 @@
|
|
|
35
40
|
- Related integrations: INT-PANDOC.
|
|
36
41
|
|
|
37
42
|
## FLOW-PROOF-RELEASE
|
|
43
|
+
label: "Run strict checks, build outputs, export artifacts, and archive release files."
|
|
38
44
|
|
|
39
45
|
- Run strict checks, build outputs, export artifacts, and archive release files.
|
|
40
46
|
- Related commands: CMD-CHECK-STAGE, CMD-BUILD, CMD-EXPORT.
|