@deskwork/core 0.9.5
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/dist/body-state.d.ts +27 -0
- package/dist/body-state.d.ts.map +1 -0
- package/dist/body-state.js +62 -0
- package/dist/body-state.js.map +1 -0
- package/dist/calendar-mutations.d.ts +124 -0
- package/dist/calendar-mutations.d.ts.map +1 -0
- package/dist/calendar-mutations.js +305 -0
- package/dist/calendar-mutations.js.map +1 -0
- package/dist/calendar.d.ts +54 -0
- package/dist/calendar.d.ts.map +1 -0
- package/dist/calendar.js +430 -0
- package/dist/calendar.js.map +1 -0
- package/dist/cli.d.ts +38 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +72 -0
- package/dist/cli.js.map +1 -0
- package/dist/config.d.ts +91 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +216 -0
- package/dist/config.js.map +1 -0
- package/dist/content-index.d.ts +74 -0
- package/dist/content-index.d.ts.map +1 -0
- package/dist/content-index.js +205 -0
- package/dist/content-index.js.map +1 -0
- package/dist/content-tree-fs-walk.d.ts +54 -0
- package/dist/content-tree-fs-walk.d.ts.map +1 -0
- package/dist/content-tree-fs-walk.js +112 -0
- package/dist/content-tree-fs-walk.js.map +1 -0
- package/dist/content-tree-helpers.d.ts +52 -0
- package/dist/content-tree-helpers.d.ts.map +1 -0
- package/dist/content-tree-helpers.js +116 -0
- package/dist/content-tree-helpers.js.map +1 -0
- package/dist/content-tree-types.d.ts +175 -0
- package/dist/content-tree-types.d.ts.map +1 -0
- package/dist/content-tree-types.js +10 -0
- package/dist/content-tree-types.js.map +1 -0
- package/dist/content-tree.d.ts +93 -0
- package/dist/content-tree.d.ts.map +1 -0
- package/dist/content-tree.js +385 -0
- package/dist/content-tree.js.map +1 -0
- package/dist/doctor/index.d.ts +11 -0
- package/dist/doctor/index.d.ts.map +1 -0
- package/dist/doctor/index.js +10 -0
- package/dist/doctor/index.js.map +1 -0
- package/dist/doctor/project-rules.d.ts +59 -0
- package/dist/doctor/project-rules.d.ts.map +1 -0
- package/dist/doctor/project-rules.js +143 -0
- package/dist/doctor/project-rules.js.map +1 -0
- package/dist/doctor/rules/calendar-uuid-missing.d.ts +19 -0
- package/dist/doctor/rules/calendar-uuid-missing.d.ts.map +1 -0
- package/dist/doctor/rules/calendar-uuid-missing.js +176 -0
- package/dist/doctor/rules/calendar-uuid-missing.js.map +1 -0
- package/dist/doctor/rules/duplicate-id.d.ts +27 -0
- package/dist/doctor/rules/duplicate-id.d.ts.map +1 -0
- package/dist/doctor/rules/duplicate-id.js +157 -0
- package/dist/doctor/rules/duplicate-id.js.map +1 -0
- package/dist/doctor/rules/legacy-top-level-id-migration.d.ts +40 -0
- package/dist/doctor/rules/legacy-top-level-id-migration.d.ts.map +1 -0
- package/dist/doctor/rules/legacy-top-level-id-migration.js +232 -0
- package/dist/doctor/rules/legacy-top-level-id-migration.js.map +1 -0
- package/dist/doctor/rules/missing-frontmatter-id.d.ts +45 -0
- package/dist/doctor/rules/missing-frontmatter-id.d.ts.map +1 -0
- package/dist/doctor/rules/missing-frontmatter-id.js +283 -0
- package/dist/doctor/rules/missing-frontmatter-id.js.map +1 -0
- package/dist/doctor/rules/orphan-frontmatter-id.d.ts +18 -0
- package/dist/doctor/rules/orphan-frontmatter-id.d.ts.map +1 -0
- package/dist/doctor/rules/orphan-frontmatter-id.js +154 -0
- package/dist/doctor/rules/orphan-frontmatter-id.js.map +1 -0
- package/dist/doctor/rules/schema-rejected.d.ts +20 -0
- package/dist/doctor/rules/schema-rejected.d.ts.map +1 -0
- package/dist/doctor/rules/schema-rejected.js +44 -0
- package/dist/doctor/rules/schema-rejected.js.map +1 -0
- package/dist/doctor/rules/slug-collision.d.ts +18 -0
- package/dist/doctor/rules/slug-collision.d.ts.map +1 -0
- package/dist/doctor/rules/slug-collision.js +65 -0
- package/dist/doctor/rules/slug-collision.js.map +1 -0
- package/dist/doctor/rules/workflow-stale.d.ts +20 -0
- package/dist/doctor/rules/workflow-stale.d.ts.map +1 -0
- package/dist/doctor/rules/workflow-stale.js +136 -0
- package/dist/doctor/rules/workflow-stale.js.map +1 -0
- package/dist/doctor/runner.d.ts +75 -0
- package/dist/doctor/runner.d.ts.map +1 -0
- package/dist/doctor/runner.js +289 -0
- package/dist/doctor/runner.js.map +1 -0
- package/dist/doctor/schema-patch.d.ts +21 -0
- package/dist/doctor/schema-patch.d.ts.map +1 -0
- package/dist/doctor/schema-patch.js +92 -0
- package/dist/doctor/schema-patch.js.map +1 -0
- package/dist/doctor/types.d.ts +185 -0
- package/dist/doctor/types.d.ts.map +1 -0
- package/dist/doctor/types.js +13 -0
- package/dist/doctor/types.js.map +1 -0
- package/dist/frontmatter.d.ts +103 -0
- package/dist/frontmatter.d.ts.map +1 -0
- package/dist/frontmatter.js +306 -0
- package/dist/frontmatter.js.map +1 -0
- package/dist/index.d.ts +27 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +27 -0
- package/dist/index.js.map +1 -0
- package/dist/ingest-derive.d.ts +79 -0
- package/dist/ingest-derive.d.ts.map +1 -0
- package/dist/ingest-derive.js +299 -0
- package/dist/ingest-derive.js.map +1 -0
- package/dist/ingest-paths.d.ts +37 -0
- package/dist/ingest-paths.d.ts.map +1 -0
- package/dist/ingest-paths.js +176 -0
- package/dist/ingest-paths.js.map +1 -0
- package/dist/ingest.d.ts +162 -0
- package/dist/ingest.d.ts.map +1 -0
- package/dist/ingest.js +269 -0
- package/dist/ingest.js.map +1 -0
- package/dist/journal.d.ts +49 -0
- package/dist/journal.d.ts.map +1 -0
- package/dist/journal.js +113 -0
- package/dist/journal.js.map +1 -0
- package/dist/outline-split.d.ts +38 -0
- package/dist/outline-split.d.ts.map +1 -0
- package/dist/outline-split.js +84 -0
- package/dist/outline-split.js.map +1 -0
- package/dist/overrides.d.ts +83 -0
- package/dist/overrides.d.ts.map +1 -0
- package/dist/overrides.js +88 -0
- package/dist/overrides.js.map +1 -0
- package/dist/paths.d.ts +183 -0
- package/dist/paths.d.ts.map +1 -0
- package/dist/paths.js +266 -0
- package/dist/paths.js.map +1 -0
- package/dist/remark-image-figure.mjs +77 -0
- package/dist/remark-strip-first-h1.mjs +26 -0
- package/dist/remark-strip-outline.mjs +44 -0
- package/dist/rename-slug.d.ts +49 -0
- package/dist/rename-slug.d.ts.map +1 -0
- package/dist/rename-slug.js +161 -0
- package/dist/rename-slug.js.map +1 -0
- package/dist/review/handlers.d.ts +55 -0
- package/dist/review/handlers.d.ts.map +1 -0
- package/dist/review/handlers.js +307 -0
- package/dist/review/handlers.js.map +1 -0
- package/dist/review/index.d.ts +14 -0
- package/dist/review/index.d.ts.map +1 -0
- package/dist/review/index.js +13 -0
- package/dist/review/index.js.map +1 -0
- package/dist/review/journal-mappers.d.ts +35 -0
- package/dist/review/journal-mappers.d.ts.map +1 -0
- package/dist/review/journal-mappers.js +48 -0
- package/dist/review/journal-mappers.js.map +1 -0
- package/dist/review/pipeline.d.ts +79 -0
- package/dist/review/pipeline.d.ts.map +1 -0
- package/dist/review/pipeline.js +234 -0
- package/dist/review/pipeline.js.map +1 -0
- package/dist/review/render.d.ts +27 -0
- package/dist/review/render.d.ts.map +1 -0
- package/dist/review/render.js +42 -0
- package/dist/review/render.js.map +1 -0
- package/dist/review/report.d.ts +50 -0
- package/dist/review/report.d.ts.map +1 -0
- package/dist/review/report.js +164 -0
- package/dist/review/report.js.map +1 -0
- package/dist/review/result.d.ts +12 -0
- package/dist/review/result.d.ts.map +1 -0
- package/dist/review/result.js +12 -0
- package/dist/review/result.js.map +1 -0
- package/dist/review/start-handlers.d.ts +62 -0
- package/dist/review/start-handlers.d.ts.map +1 -0
- package/dist/review/start-handlers.js +223 -0
- package/dist/review/start-handlers.js.map +1 -0
- package/dist/review/types.d.ts +169 -0
- package/dist/review/types.d.ts.map +1 -0
- package/dist/review/types.js +26 -0
- package/dist/review/types.js.map +1 -0
- package/dist/review/workflow-paths.d.ts +68 -0
- package/dist/review/workflow-paths.d.ts.map +1 -0
- package/dist/review/workflow-paths.js +112 -0
- package/dist/review/workflow-paths.js.map +1 -0
- package/dist/scaffold.d.ts +67 -0
- package/dist/scaffold.d.ts.map +1 -0
- package/dist/scaffold.js +122 -0
- package/dist/scaffold.js.map +1 -0
- package/dist/scrapbook.d.ts +229 -0
- package/dist/scrapbook.d.ts.map +1 -0
- package/dist/scrapbook.js +500 -0
- package/dist/scrapbook.js.map +1 -0
- package/dist/types.d.ts +197 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +120 -0
- package/dist/types.js.map +1 -0
- package/package.json +160 -0
package/dist/calendar.js
ADDED
|
@@ -0,0 +1,430 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Markdown editorial calendar parser and writer.
|
|
3
|
+
*
|
|
4
|
+
* Each site's calendar is a human-readable markdown file with one table per
|
|
5
|
+
* stage. This module round-trips between that format and the in-memory
|
|
6
|
+
* EditorialCalendar type.
|
|
7
|
+
*
|
|
8
|
+
* ## Markdown format
|
|
9
|
+
*
|
|
10
|
+
* ```markdown
|
|
11
|
+
* # Editorial Calendar
|
|
12
|
+
*
|
|
13
|
+
* ## Ideas
|
|
14
|
+
*
|
|
15
|
+
* | UUID | Slug | Title | Description | Keywords | Source |
|
|
16
|
+
* |------|------|-------|-------------|----------|--------|
|
|
17
|
+
* | abc-123 | my-post | My Post | A post about things | kw1, kw2 | manual |
|
|
18
|
+
*
|
|
19
|
+
* ## Planned
|
|
20
|
+
* ...
|
|
21
|
+
*
|
|
22
|
+
* ## Published
|
|
23
|
+
*
|
|
24
|
+
* | UUID | Slug | Title | Description | Keywords | Source | Published | Issue |
|
|
25
|
+
* |------|------|-------|-------------|----------|--------|-----------|-------|
|
|
26
|
+
* ```
|
|
27
|
+
*
|
|
28
|
+
* Optional columns (Topics, Type, URL) are emitted only when any entry uses
|
|
29
|
+
* them, so a calendar with no cross-posting stays visually simple. Published
|
|
30
|
+
* entries always include Published and Issue columns. The UUID column is
|
|
31
|
+
* always emitted at render time — pre-UUID calendars get backfilled lazily
|
|
32
|
+
* (parser assigns missing UUIDs in-memory; the next write persists them).
|
|
33
|
+
*/
|
|
34
|
+
import { readFileSync, writeFileSync } from 'node:fs';
|
|
35
|
+
import { randomUUID } from 'node:crypto';
|
|
36
|
+
import { PLATFORMS, STAGES, effectiveContentType, isContentType, isPausable, isPlatform, isStage, } from "./types.js";
|
|
37
|
+
// ---------------------------------------------------------------------------
|
|
38
|
+
// Parser
|
|
39
|
+
// ---------------------------------------------------------------------------
|
|
40
|
+
function parseRow(line) {
|
|
41
|
+
return line
|
|
42
|
+
.split('|')
|
|
43
|
+
.slice(1, -1)
|
|
44
|
+
.map((cell) => cell.trim());
|
|
45
|
+
}
|
|
46
|
+
function isSeparator(line) {
|
|
47
|
+
return /^\|[\s:-]+\|/.test(line);
|
|
48
|
+
}
|
|
49
|
+
function indexColumns(headerLine) {
|
|
50
|
+
const map = new Map();
|
|
51
|
+
parseRow(headerLine).forEach((name, idx) => {
|
|
52
|
+
map.set(name.trim().toLowerCase(), idx);
|
|
53
|
+
});
|
|
54
|
+
return map;
|
|
55
|
+
}
|
|
56
|
+
function col(cells, cols, name) {
|
|
57
|
+
const idx = cols.get(name);
|
|
58
|
+
if (idx === undefined)
|
|
59
|
+
return undefined;
|
|
60
|
+
const value = cells[idx];
|
|
61
|
+
if (value === undefined)
|
|
62
|
+
return undefined;
|
|
63
|
+
const trimmed = value.trim();
|
|
64
|
+
return trimmed === '' ? undefined : trimmed;
|
|
65
|
+
}
|
|
66
|
+
function parseEntries(lines, stage) {
|
|
67
|
+
const entries = [];
|
|
68
|
+
let i = 0;
|
|
69
|
+
while (i < lines.length && !lines[i].startsWith('|'))
|
|
70
|
+
i++;
|
|
71
|
+
if (i >= lines.length)
|
|
72
|
+
return entries;
|
|
73
|
+
const cols = indexColumns(lines[i]);
|
|
74
|
+
i++;
|
|
75
|
+
if (i < lines.length && isSeparator(lines[i]))
|
|
76
|
+
i++;
|
|
77
|
+
while (i < lines.length && lines[i].startsWith('|')) {
|
|
78
|
+
const cells = parseRow(lines[i]);
|
|
79
|
+
const slug = col(cells, cols, 'slug');
|
|
80
|
+
const title = col(cells, cols, 'title');
|
|
81
|
+
if (slug && title) {
|
|
82
|
+
// UUID column is optional for backward compatibility. Missing IDs
|
|
83
|
+
// get a fresh v4 assigned in-memory; the next writeCalendar
|
|
84
|
+
// persists them, so one save fully migrates a legacy calendar.
|
|
85
|
+
const existingId = col(cells, cols, 'uuid') ?? col(cells, cols, 'id');
|
|
86
|
+
const entry = {
|
|
87
|
+
id: existingId ?? randomUUID(),
|
|
88
|
+
slug,
|
|
89
|
+
title,
|
|
90
|
+
description: col(cells, cols, 'description') ?? '',
|
|
91
|
+
stage,
|
|
92
|
+
targetKeywords: (col(cells, cols, 'keywords') ?? '')
|
|
93
|
+
.split(',')
|
|
94
|
+
.map((k) => k.trim())
|
|
95
|
+
.filter(Boolean),
|
|
96
|
+
source: col(cells, cols, 'source') === 'analytics' ? 'analytics' : 'manual',
|
|
97
|
+
};
|
|
98
|
+
const topics = col(cells, cols, 'topics');
|
|
99
|
+
if (topics) {
|
|
100
|
+
entry.topics = topics.split(',').map((t) => t.trim()).filter(Boolean);
|
|
101
|
+
}
|
|
102
|
+
const typeValue = col(cells, cols, 'type');
|
|
103
|
+
if (typeValue && isContentType(typeValue)) {
|
|
104
|
+
entry.contentType = typeValue;
|
|
105
|
+
}
|
|
106
|
+
const url = col(cells, cols, 'url');
|
|
107
|
+
if (url)
|
|
108
|
+
entry.contentUrl = url;
|
|
109
|
+
// Legacy calendars may carry a `FilePath` column from the prior
|
|
110
|
+
// plan; the parser is column-tolerant and ignores it. Phase 19
|
|
111
|
+
// moves filesystem placement to frontmatter `id:` + the content
|
|
112
|
+
// index, so the column is no longer load-bearing on disk.
|
|
113
|
+
// PausedFrom column round-trips on the Paused section. Other
|
|
114
|
+
// sections that happen to carry the column (legacy hand-edits)
|
|
115
|
+
// ignore the value since `entry.stage !== 'Paused'`.
|
|
116
|
+
const pausedFrom = col(cells, cols, 'pausedfrom');
|
|
117
|
+
if (pausedFrom && isStage(pausedFrom) && isPausable(pausedFrom)) {
|
|
118
|
+
entry.pausedFrom = pausedFrom;
|
|
119
|
+
}
|
|
120
|
+
const published = col(cells, cols, 'published');
|
|
121
|
+
if (published)
|
|
122
|
+
entry.datePublished = published;
|
|
123
|
+
const issue = col(cells, cols, 'issue');
|
|
124
|
+
if (issue) {
|
|
125
|
+
const match = issue.match(/#?(\d+)/);
|
|
126
|
+
if (match)
|
|
127
|
+
entry.issueNumber = parseInt(match[1], 10);
|
|
128
|
+
}
|
|
129
|
+
entries.push(entry);
|
|
130
|
+
}
|
|
131
|
+
i++;
|
|
132
|
+
}
|
|
133
|
+
return entries;
|
|
134
|
+
}
|
|
135
|
+
function parseDistributions(lines) {
|
|
136
|
+
const records = [];
|
|
137
|
+
let i = 0;
|
|
138
|
+
while (i < lines.length && !lines[i].startsWith('|'))
|
|
139
|
+
i++;
|
|
140
|
+
if (i >= lines.length)
|
|
141
|
+
return records;
|
|
142
|
+
const cols = indexColumns(lines[i]);
|
|
143
|
+
i++;
|
|
144
|
+
if (i < lines.length && isSeparator(lines[i]))
|
|
145
|
+
i++;
|
|
146
|
+
while (i < lines.length && lines[i].startsWith('|')) {
|
|
147
|
+
const cells = parseRow(lines[i]);
|
|
148
|
+
const slug = col(cells, cols, 'slug');
|
|
149
|
+
const platformValue = col(cells, cols, 'platform');
|
|
150
|
+
const url = col(cells, cols, 'url');
|
|
151
|
+
const dateShared = col(cells, cols, 'shared');
|
|
152
|
+
// Phase 21a: URL may be empty at creation time (a placeholder
|
|
153
|
+
// distribution record awaiting the operator's posted URL via
|
|
154
|
+
// updateDistributionUrl). Parser accepts empty URL; only slug,
|
|
155
|
+
// platform, and dateShared are required for round-trip.
|
|
156
|
+
if (slug && platformValue && dateShared && isPlatform(platformValue)) {
|
|
157
|
+
// entryId may be missing on legacy rows. Left empty here and
|
|
158
|
+
// backfilled in parseCalendar once entries are parsed and a
|
|
159
|
+
// slug → entry lookup table is available.
|
|
160
|
+
const entryIdCell = col(cells, cols, 'entryid') ?? col(cells, cols, 'uuid');
|
|
161
|
+
const rec = {
|
|
162
|
+
entryId: entryIdCell ?? '',
|
|
163
|
+
slug,
|
|
164
|
+
platform: platformValue,
|
|
165
|
+
url: url ?? '',
|
|
166
|
+
dateShared,
|
|
167
|
+
};
|
|
168
|
+
const channel = col(cells, cols, 'channel');
|
|
169
|
+
if (channel)
|
|
170
|
+
rec.channel = channel;
|
|
171
|
+
const notes = col(cells, cols, 'notes');
|
|
172
|
+
if (notes)
|
|
173
|
+
rec.notes = notes;
|
|
174
|
+
records.push(rec);
|
|
175
|
+
}
|
|
176
|
+
i++;
|
|
177
|
+
}
|
|
178
|
+
return records;
|
|
179
|
+
}
|
|
180
|
+
function parseShortformBlocks(lines) {
|
|
181
|
+
const blocks = [];
|
|
182
|
+
let i = 0;
|
|
183
|
+
while (i < lines.length) {
|
|
184
|
+
const header = lines[i].match(/^### (.+)$/);
|
|
185
|
+
if (!header) {
|
|
186
|
+
i++;
|
|
187
|
+
continue;
|
|
188
|
+
}
|
|
189
|
+
const parts = header[1].split('·').map((s) => s.trim());
|
|
190
|
+
if (parts.length < 2) {
|
|
191
|
+
i++;
|
|
192
|
+
continue;
|
|
193
|
+
}
|
|
194
|
+
const [slug, platform, channel] = parts;
|
|
195
|
+
i++;
|
|
196
|
+
const bodyLines = [];
|
|
197
|
+
while (i < lines.length && !lines[i].startsWith('### ')) {
|
|
198
|
+
bodyLines.push(lines[i]);
|
|
199
|
+
i++;
|
|
200
|
+
}
|
|
201
|
+
const text = bodyLines.join('\n').replace(/^\n+|\n+$/g, '');
|
|
202
|
+
if (text.length > 0) {
|
|
203
|
+
const block = { slug, platform, text };
|
|
204
|
+
if (channel)
|
|
205
|
+
block.channel = channel;
|
|
206
|
+
blocks.push(block);
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
return blocks;
|
|
210
|
+
}
|
|
211
|
+
/** Parse the editorial calendar markdown file into an EditorialCalendar. */
|
|
212
|
+
export function parseCalendar(markdown) {
|
|
213
|
+
const entries = [];
|
|
214
|
+
const distributions = [];
|
|
215
|
+
const shortformBlocks = [];
|
|
216
|
+
const lines = markdown.split('\n');
|
|
217
|
+
let currentSection = null;
|
|
218
|
+
let sectionLines = [];
|
|
219
|
+
function flushSection() {
|
|
220
|
+
if (currentSection && sectionLines.length > 0) {
|
|
221
|
+
if (currentSection === 'Distribution') {
|
|
222
|
+
distributions.push(...parseDistributions(sectionLines));
|
|
223
|
+
}
|
|
224
|
+
else if (currentSection === 'Shortform Copy') {
|
|
225
|
+
shortformBlocks.push(...parseShortformBlocks(sectionLines));
|
|
226
|
+
}
|
|
227
|
+
else {
|
|
228
|
+
entries.push(...parseEntries(sectionLines, currentSection));
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
sectionLines = [];
|
|
232
|
+
}
|
|
233
|
+
for (const line of lines) {
|
|
234
|
+
const sectionMatch = line.match(/^## (.+)$/);
|
|
235
|
+
if (sectionMatch) {
|
|
236
|
+
flushSection();
|
|
237
|
+
const name = sectionMatch[1].trim();
|
|
238
|
+
if (isStage(name)) {
|
|
239
|
+
currentSection = name;
|
|
240
|
+
}
|
|
241
|
+
else if (name === 'Distribution') {
|
|
242
|
+
currentSection = 'Distribution';
|
|
243
|
+
}
|
|
244
|
+
else if (name === 'Shortform Copy') {
|
|
245
|
+
currentSection = 'Shortform Copy';
|
|
246
|
+
}
|
|
247
|
+
else {
|
|
248
|
+
currentSection = null;
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
else if (currentSection) {
|
|
252
|
+
sectionLines.push(line);
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
flushSection();
|
|
256
|
+
// Merge shortform blocks onto their matching DistributionRecord by
|
|
257
|
+
// (slug, platform, channel) — normalize channel to avoid case drift.
|
|
258
|
+
for (const b of shortformBlocks) {
|
|
259
|
+
const rec = distributions.find((d) => d.slug === b.slug &&
|
|
260
|
+
d.platform === b.platform &&
|
|
261
|
+
(d.channel ?? '').toLowerCase() === (b.channel ?? '').toLowerCase());
|
|
262
|
+
if (rec)
|
|
263
|
+
rec.shortform = b.text;
|
|
264
|
+
}
|
|
265
|
+
// Backfill missing entryIds on DistributionRecords by slug match
|
|
266
|
+
// against the entries we just parsed. Records whose slug doesn't
|
|
267
|
+
// resolve to a known entry keep an empty entryId — writeCalendar
|
|
268
|
+
// preserves that (the row is still parseable), and a subsequent
|
|
269
|
+
// distribute or migration run will fix it.
|
|
270
|
+
const entryBySlug = new Map(entries.map((e) => [e.slug, e]));
|
|
271
|
+
for (const d of distributions) {
|
|
272
|
+
if (!d.entryId) {
|
|
273
|
+
const match = entryBySlug.get(d.slug);
|
|
274
|
+
if (match && match.id)
|
|
275
|
+
d.entryId = match.id;
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
return { entries, distributions };
|
|
279
|
+
}
|
|
280
|
+
/**
|
|
281
|
+
* Read and parse the editorial calendar from an absolute path.
|
|
282
|
+
*
|
|
283
|
+
* A non-existent file is treated as a logically empty calendar — the user
|
|
284
|
+
* hasn't written anything yet. Any other error (e.g. unreadable, malformed)
|
|
285
|
+
* propagates so the operator sees the problem instead of a silently-empty
|
|
286
|
+
* dashboard.
|
|
287
|
+
*/
|
|
288
|
+
export function readCalendar(calendarPath) {
|
|
289
|
+
let raw;
|
|
290
|
+
try {
|
|
291
|
+
raw = readFileSync(calendarPath, 'utf-8');
|
|
292
|
+
}
|
|
293
|
+
catch (err) {
|
|
294
|
+
if (err instanceof Error && 'code' in err && err.code === 'ENOENT') {
|
|
295
|
+
return { entries: [], distributions: [] };
|
|
296
|
+
}
|
|
297
|
+
throw err;
|
|
298
|
+
}
|
|
299
|
+
return parseCalendar(raw);
|
|
300
|
+
}
|
|
301
|
+
// ---------------------------------------------------------------------------
|
|
302
|
+
// Writer
|
|
303
|
+
// ---------------------------------------------------------------------------
|
|
304
|
+
function escapeCell(value) {
|
|
305
|
+
return value.replace(/\|/g, '\\|');
|
|
306
|
+
}
|
|
307
|
+
function renderStageTable(entries, stage) {
|
|
308
|
+
const lines = [];
|
|
309
|
+
const hasIssue = entries.some((e) => e.issueNumber !== undefined);
|
|
310
|
+
const hasTopics = entries.some((e) => e.topics !== undefined && e.topics.length > 0);
|
|
311
|
+
const hasType = entries.some((e) => e.contentType !== undefined && e.contentType !== 'blog');
|
|
312
|
+
const hasUrl = entries.some((e) => e.contentUrl !== undefined && e.contentUrl !== '');
|
|
313
|
+
const isPublished = stage === 'Published';
|
|
314
|
+
const isPaused = stage === 'Paused';
|
|
315
|
+
const headers = ['UUID', 'Slug', 'Title', 'Description', 'Keywords'];
|
|
316
|
+
if (hasTopics)
|
|
317
|
+
headers.push('Topics');
|
|
318
|
+
if (hasType)
|
|
319
|
+
headers.push('Type');
|
|
320
|
+
if (hasUrl)
|
|
321
|
+
headers.push('URL');
|
|
322
|
+
headers.push('Source');
|
|
323
|
+
if (isPaused)
|
|
324
|
+
headers.push('PausedFrom');
|
|
325
|
+
if (isPublished)
|
|
326
|
+
headers.push('Published');
|
|
327
|
+
if (hasIssue || isPublished)
|
|
328
|
+
headers.push('Issue');
|
|
329
|
+
lines.push(`| ${headers.join(' | ')} |`);
|
|
330
|
+
lines.push(`|${headers.map(() => '------').join('|')}|`);
|
|
331
|
+
for (const e of entries) {
|
|
332
|
+
// Backfill a UUID at render time if one is missing. Mutates the
|
|
333
|
+
// entry so subsequent reads/writes see a stable id.
|
|
334
|
+
if (!e.id)
|
|
335
|
+
e.id = randomUUID();
|
|
336
|
+
const row = [
|
|
337
|
+
e.id,
|
|
338
|
+
escapeCell(e.slug),
|
|
339
|
+
escapeCell(e.title),
|
|
340
|
+
escapeCell(e.description),
|
|
341
|
+
escapeCell(e.targetKeywords.join(', ')),
|
|
342
|
+
];
|
|
343
|
+
if (hasTopics)
|
|
344
|
+
row.push(escapeCell((e.topics ?? []).join(', ')));
|
|
345
|
+
if (hasType)
|
|
346
|
+
row.push(effectiveContentType(e));
|
|
347
|
+
if (hasUrl)
|
|
348
|
+
row.push(escapeCell(e.contentUrl ?? ''));
|
|
349
|
+
row.push(e.source);
|
|
350
|
+
if (isPaused)
|
|
351
|
+
row.push(e.pausedFrom ?? '');
|
|
352
|
+
if (isPublished)
|
|
353
|
+
row.push(e.datePublished ?? '');
|
|
354
|
+
if (hasIssue || isPublished)
|
|
355
|
+
row.push(e.issueNumber ? `#${e.issueNumber}` : '');
|
|
356
|
+
lines.push(`| ${row.join(' | ')} |`);
|
|
357
|
+
}
|
|
358
|
+
return lines.join('\n');
|
|
359
|
+
}
|
|
360
|
+
function renderDistributionTable(records) {
|
|
361
|
+
const lines = [];
|
|
362
|
+
const hasChannel = records.some((r) => r.channel !== undefined && r.channel !== '');
|
|
363
|
+
const headers = ['EntryID', 'Slug', 'Platform', 'URL', 'Shared'];
|
|
364
|
+
if (hasChannel)
|
|
365
|
+
headers.push('Channel');
|
|
366
|
+
headers.push('Notes');
|
|
367
|
+
lines.push(`| ${headers.join(' | ')} |`);
|
|
368
|
+
lines.push(`|${headers.map(() => '------').join('|')}|`);
|
|
369
|
+
for (const r of records) {
|
|
370
|
+
const row = [
|
|
371
|
+
r.entryId ?? '',
|
|
372
|
+
escapeCell(r.slug),
|
|
373
|
+
r.platform,
|
|
374
|
+
escapeCell(r.url),
|
|
375
|
+
r.dateShared,
|
|
376
|
+
];
|
|
377
|
+
if (hasChannel)
|
|
378
|
+
row.push(escapeCell(r.channel ?? ''));
|
|
379
|
+
row.push(escapeCell(r.notes ?? ''));
|
|
380
|
+
lines.push(`| ${row.join(' | ')} |`);
|
|
381
|
+
}
|
|
382
|
+
return lines.join('\n');
|
|
383
|
+
}
|
|
384
|
+
/** Render the full editorial calendar as markdown. */
|
|
385
|
+
export function renderCalendar(calendar) {
|
|
386
|
+
const sections = ['# Editorial Calendar', ''];
|
|
387
|
+
for (const stage of STAGES) {
|
|
388
|
+
const stageEntries = calendar.entries.filter((e) => e.stage === stage);
|
|
389
|
+
sections.push(`## ${stage}`, '');
|
|
390
|
+
if (stageEntries.length > 0) {
|
|
391
|
+
sections.push(renderStageTable(stageEntries, stage));
|
|
392
|
+
}
|
|
393
|
+
else {
|
|
394
|
+
sections.push('*No entries.*');
|
|
395
|
+
}
|
|
396
|
+
sections.push('');
|
|
397
|
+
}
|
|
398
|
+
sections.push('## Distribution', '');
|
|
399
|
+
if (calendar.distributions.length > 0) {
|
|
400
|
+
sections.push(renderDistributionTable(calendar.distributions));
|
|
401
|
+
}
|
|
402
|
+
else {
|
|
403
|
+
sections.push('*No entries.*');
|
|
404
|
+
}
|
|
405
|
+
sections.push('');
|
|
406
|
+
const shortformRecords = calendar.distributions.filter((d) => d.shortform !== undefined && d.shortform !== '');
|
|
407
|
+
if (shortformRecords.length > 0) {
|
|
408
|
+
sections.push('## Shortform Copy', '');
|
|
409
|
+
for (const r of shortformRecords) {
|
|
410
|
+
const headerParts = [r.slug, r.platform];
|
|
411
|
+
if (r.channel)
|
|
412
|
+
headerParts.push(r.channel);
|
|
413
|
+
sections.push(`### ${headerParts.join(' · ')}`, '');
|
|
414
|
+
sections.push((r.shortform ?? '').replace(/\n+$/, ''));
|
|
415
|
+
sections.push('');
|
|
416
|
+
}
|
|
417
|
+
}
|
|
418
|
+
return sections.join('\n');
|
|
419
|
+
}
|
|
420
|
+
/** Write the editorial calendar to an absolute path. */
|
|
421
|
+
export function writeCalendar(calendarPath, calendar) {
|
|
422
|
+
writeFileSync(calendarPath, renderCalendar(calendar), 'utf-8');
|
|
423
|
+
}
|
|
424
|
+
/** Render an empty calendar — used by the install skill to seed a new file. */
|
|
425
|
+
export function renderEmptyCalendar() {
|
|
426
|
+
return renderCalendar({ entries: [], distributions: [] });
|
|
427
|
+
}
|
|
428
|
+
/** Suppress unused-import warnings for re-exported constants available to callers. */
|
|
429
|
+
export { PLATFORMS, STAGES };
|
|
430
|
+
//# sourceMappingURL=calendar.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"calendar.js","sourceRoot":"","sources":["../src/calendar.ts"],"names":[],"mappings":"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"}
|
package/dist/cli.d.ts
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tiny argv helpers shared by the bin/ scripts.
|
|
3
|
+
*
|
|
4
|
+
* We intentionally avoid pulling in a heavyweight CLI framework — each
|
|
5
|
+
* helper has a small surface, and hand-rolled parsing keeps the scripts
|
|
6
|
+
* transparent. Unknown flags throw so typos surface as an error instead of
|
|
7
|
+
* being silently ignored.
|
|
8
|
+
*/
|
|
9
|
+
export interface ParsedArgs {
|
|
10
|
+
/** Positional args in order. */
|
|
11
|
+
positional: string[];
|
|
12
|
+
/** Flags and their string values; repeated flags overwrite. */
|
|
13
|
+
flags: Record<string, string>;
|
|
14
|
+
/** Boolean flags present on the command line (no value). */
|
|
15
|
+
booleans: Set<string>;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Parse argv into positionals, `--flag value` pairs, and boolean flags.
|
|
19
|
+
*
|
|
20
|
+
* @param argv The argv slice to parse (e.g. `process.argv.slice(2)`).
|
|
21
|
+
* @param known Flag names that accept a following value.
|
|
22
|
+
* @param booleanFlags Flag names that are boolean (no value follows).
|
|
23
|
+
*
|
|
24
|
+
* Throws on unknown flags and missing values.
|
|
25
|
+
*/
|
|
26
|
+
export declare function parseArgs(argv: string[], known: readonly string[], booleanFlags?: readonly string[]): ParsedArgs;
|
|
27
|
+
/** Resolve a path arg to an absolute path, relative to cwd when not absolute. */
|
|
28
|
+
export declare function absolutize(pathArg: string): string;
|
|
29
|
+
/**
|
|
30
|
+
* Print a fatal error message to stderr and exit non-zero.
|
|
31
|
+
*
|
|
32
|
+
* Use this for user-facing failures (bad args, missing files, schema errors).
|
|
33
|
+
* Developer errors (bugs) should throw and let the stack trace through.
|
|
34
|
+
*/
|
|
35
|
+
export declare function fail(message: string, code?: number): never;
|
|
36
|
+
/** Print a JSON result to stdout followed by a newline. */
|
|
37
|
+
export declare function emit(result: unknown): void;
|
|
38
|
+
//# sourceMappingURL=cli.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAIH,MAAM,WAAW,UAAU;IACzB,gCAAgC;IAChC,UAAU,EAAE,MAAM,EAAE,CAAC;IACrB,+DAA+D;IAC/D,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC9B,4DAA4D;IAC5D,QAAQ,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;CACvB;AAED;;;;;;;;GAQG;AACH,wBAAgB,SAAS,CACvB,IAAI,EAAE,MAAM,EAAE,EACd,KAAK,EAAE,SAAS,MAAM,EAAE,EACxB,YAAY,GAAE,SAAS,MAAM,EAAO,GACnC,UAAU,CAkCZ;AAED,iFAAiF;AACjF,wBAAgB,UAAU,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAElD;AAED;;;;;GAKG;AACH,wBAAgB,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,SAAI,GAAG,KAAK,CAGrD;AAED,2DAA2D;AAC3D,wBAAgB,IAAI,CAAC,MAAM,EAAE,OAAO,GAAG,IAAI,CAE1C"}
|
package/dist/cli.js
ADDED
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tiny argv helpers shared by the bin/ scripts.
|
|
3
|
+
*
|
|
4
|
+
* We intentionally avoid pulling in a heavyweight CLI framework — each
|
|
5
|
+
* helper has a small surface, and hand-rolled parsing keeps the scripts
|
|
6
|
+
* transparent. Unknown flags throw so typos surface as an error instead of
|
|
7
|
+
* being silently ignored.
|
|
8
|
+
*/
|
|
9
|
+
import { isAbsolute, resolve } from 'node:path';
|
|
10
|
+
/**
|
|
11
|
+
* Parse argv into positionals, `--flag value` pairs, and boolean flags.
|
|
12
|
+
*
|
|
13
|
+
* @param argv The argv slice to parse (e.g. `process.argv.slice(2)`).
|
|
14
|
+
* @param known Flag names that accept a following value.
|
|
15
|
+
* @param booleanFlags Flag names that are boolean (no value follows).
|
|
16
|
+
*
|
|
17
|
+
* Throws on unknown flags and missing values.
|
|
18
|
+
*/
|
|
19
|
+
export function parseArgs(argv, known, booleanFlags = []) {
|
|
20
|
+
const positional = [];
|
|
21
|
+
const flags = {};
|
|
22
|
+
const booleans = new Set();
|
|
23
|
+
const knownSet = new Set(known);
|
|
24
|
+
const boolSet = new Set(booleanFlags);
|
|
25
|
+
for (let i = 0; i < argv.length; i++) {
|
|
26
|
+
const a = argv[i];
|
|
27
|
+
if (!a.startsWith('--')) {
|
|
28
|
+
positional.push(a);
|
|
29
|
+
continue;
|
|
30
|
+
}
|
|
31
|
+
const eq = a.indexOf('=');
|
|
32
|
+
const name = eq >= 0 ? a.slice(2, eq) : a.slice(2);
|
|
33
|
+
if (boolSet.has(name)) {
|
|
34
|
+
booleans.add(name);
|
|
35
|
+
continue;
|
|
36
|
+
}
|
|
37
|
+
if (!knownSet.has(name)) {
|
|
38
|
+
throw new Error(`Unknown flag: --${name}`);
|
|
39
|
+
}
|
|
40
|
+
if (eq >= 0) {
|
|
41
|
+
flags[name] = a.slice(eq + 1);
|
|
42
|
+
}
|
|
43
|
+
else {
|
|
44
|
+
const next = argv[i + 1];
|
|
45
|
+
if (next === undefined || next.startsWith('--')) {
|
|
46
|
+
throw new Error(`Flag --${name} requires a value`);
|
|
47
|
+
}
|
|
48
|
+
flags[name] = next;
|
|
49
|
+
i++;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
return { positional, flags, booleans };
|
|
53
|
+
}
|
|
54
|
+
/** Resolve a path arg to an absolute path, relative to cwd when not absolute. */
|
|
55
|
+
export function absolutize(pathArg) {
|
|
56
|
+
return isAbsolute(pathArg) ? pathArg : resolve(process.cwd(), pathArg);
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Print a fatal error message to stderr and exit non-zero.
|
|
60
|
+
*
|
|
61
|
+
* Use this for user-facing failures (bad args, missing files, schema errors).
|
|
62
|
+
* Developer errors (bugs) should throw and let the stack trace through.
|
|
63
|
+
*/
|
|
64
|
+
export function fail(message, code = 1) {
|
|
65
|
+
process.stderr.write(`${message}\n`);
|
|
66
|
+
process.exit(code);
|
|
67
|
+
}
|
|
68
|
+
/** Print a JSON result to stdout followed by a newline. */
|
|
69
|
+
export function emit(result) {
|
|
70
|
+
process.stdout.write(`${JSON.stringify(result, null, 2)}\n`);
|
|
71
|
+
}
|
|
72
|
+
//# sourceMappingURL=cli.js.map
|
package/dist/cli.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAE,UAAU,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAWhD;;;;;;;;GAQG;AACH,MAAM,UAAU,SAAS,CACvB,IAAc,EACd,KAAwB,EACxB,eAAkC,EAAE;IAEpC,MAAM,UAAU,GAAa,EAAE,CAAC;IAChC,MAAM,KAAK,GAA2B,EAAE,CAAC;IACzC,MAAM,QAAQ,GAAG,IAAI,GAAG,EAAU,CAAC;IACnC,MAAM,QAAQ,GAAG,IAAI,GAAG,CAAC,KAAK,CAAC,CAAC;IAChC,MAAM,OAAO,GAAG,IAAI,GAAG,CAAC,YAAY,CAAC,CAAC;IAEtC,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACrC,MAAM,CAAC,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,IAAI,CAAC,CAAC,CAAC,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC;YACxB,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;YACnB,SAAS;QACX,CAAC;QACD,MAAM,EAAE,GAAG,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;QAC1B,MAAM,IAAI,GAAG,EAAE,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;QACnD,IAAI,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC;YACtB,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;YACnB,SAAS;QACX,CAAC;QACD,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC;YACxB,MAAM,IAAI,KAAK,CAAC,mBAAmB,IAAI,EAAE,CAAC,CAAC;QAC7C,CAAC;QACD,IAAI,EAAE,IAAI,CAAC,EAAE,CAAC;YACZ,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,EAAE,GAAG,CAAC,CAAC,CAAC;QAChC,CAAC;aAAM,CAAC;YACN,MAAM,IAAI,GAAG,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;YACzB,IAAI,IAAI,KAAK,SAAS,IAAI,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC;gBAChD,MAAM,IAAI,KAAK,CAAC,UAAU,IAAI,mBAAmB,CAAC,CAAC;YACrD,CAAC;YACD,KAAK,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;YACnB,CAAC,EAAE,CAAC;QACN,CAAC;IACH,CAAC;IACD,OAAO,EAAE,UAAU,EAAE,KAAK,EAAE,QAAQ,EAAE,CAAC;AACzC,CAAC;AAED,iFAAiF;AACjF,MAAM,UAAU,UAAU,CAAC,OAAe;IACxC,OAAO,UAAU,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,OAAO,CAAC,CAAC;AACzE,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,IAAI,CAAC,OAAe,EAAE,IAAI,GAAG,CAAC;IAC5C,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,OAAO,IAAI,CAAC,CAAC;IACrC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AACrB,CAAC;AAED,2DAA2D;AAC3D,MAAM,UAAU,IAAI,CAAC,MAAe;IAClC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC;AAC/D,CAAC"}
|
package/dist/config.d.ts
ADDED
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* deskwork plugin configuration.
|
|
3
|
+
*
|
|
4
|
+
* A host project is "installed" by writing a `.deskwork/config.json` at the
|
|
5
|
+
* project root. The config tells the plugin where content lives, where to
|
|
6
|
+
* keep the editorial calendar, and which sites the project hosts.
|
|
7
|
+
*
|
|
8
|
+
* The schema is intentionally minimal — one version, one set of required
|
|
9
|
+
* fields per site, no hidden defaults. `parseConfig` validates an unknown
|
|
10
|
+
* JSON value and returns a typed DeskworkConfig or throws an Error whose
|
|
11
|
+
* message tells the user which field is wrong.
|
|
12
|
+
*/
|
|
13
|
+
/** Current config schema version. Bumped only with a migration path. */
|
|
14
|
+
export declare const CONFIG_VERSION = 1;
|
|
15
|
+
/** A single site the host project publishes to. */
|
|
16
|
+
export interface SiteConfig {
|
|
17
|
+
/**
|
|
18
|
+
* Bare public hostname, no protocol (e.g. `audiocontrol.org`). Optional —
|
|
19
|
+
* required only when the collection is rendered as a website. Internal-doc
|
|
20
|
+
* collections, books, or tool monorepos that use deskwork purely for
|
|
21
|
+
* content-lifecycle management omit this field.
|
|
22
|
+
*/
|
|
23
|
+
host?: string;
|
|
24
|
+
/** Blog content directory, relative to the project root */
|
|
25
|
+
contentDir: string;
|
|
26
|
+
/** Editorial calendar markdown file, relative to the project root */
|
|
27
|
+
calendarPath: string;
|
|
28
|
+
/** Optional cross-posting channels JSON file, relative to the project root */
|
|
29
|
+
channelsPath?: string;
|
|
30
|
+
/**
|
|
31
|
+
* Value to set on new blog posts' `layout:` frontmatter field. Typically a
|
|
32
|
+
* relative path like `../../layouts/BlogLayout.astro`. Only emitted when
|
|
33
|
+
* set — projects using Astro content collections usually leave this unset
|
|
34
|
+
* (layout resolution happens in the collection config instead).
|
|
35
|
+
*/
|
|
36
|
+
blogLayout?: string;
|
|
37
|
+
/**
|
|
38
|
+
* Path template for scaffolded blog files, relative to `contentDir`. Uses
|
|
39
|
+
* `{slug}` as the placeholder. Defaults to `"{slug}/index.md"` (directory-
|
|
40
|
+
* style). Astro content collections typically use `"{slug}.md"` (flat).
|
|
41
|
+
*/
|
|
42
|
+
blogFilenameTemplate?: string;
|
|
43
|
+
/**
|
|
44
|
+
* Value to set on the scaffolded post's `state:` frontmatter field. When
|
|
45
|
+
* set, the line `state: <value>` is emitted. Typical value: `"draft"`.
|
|
46
|
+
* Host projects that gate prod builds on `state !== "draft"` use this to
|
|
47
|
+
* keep in-flight posts out of production.
|
|
48
|
+
*/
|
|
49
|
+
blogInitialState?: string;
|
|
50
|
+
/**
|
|
51
|
+
* If true, the scaffolder inserts a `## Outline` section (with a placeholder
|
|
52
|
+
* comment) between the H1 and the body placeholder. Default false.
|
|
53
|
+
*/
|
|
54
|
+
blogOutlineSection?: boolean;
|
|
55
|
+
/**
|
|
56
|
+
* Path to the site's `_redirects` file (Netlify-style), relative to
|
|
57
|
+
* the project root. The slug-rename helper appends 301 redirects here
|
|
58
|
+
* when an existing post is renamed. Optional — when unset, slug-rename
|
|
59
|
+
* skips the redirect-append step.
|
|
60
|
+
*/
|
|
61
|
+
redirectsPath?: string;
|
|
62
|
+
}
|
|
63
|
+
/** Top-level deskwork config. */
|
|
64
|
+
export interface DeskworkConfig {
|
|
65
|
+
version: typeof CONFIG_VERSION;
|
|
66
|
+
/** Sites keyed by slug (matches the directory segment under `src/sites/<slug>/`). */
|
|
67
|
+
sites: Record<string, SiteConfig>;
|
|
68
|
+
/** Which site to target when no `--site` argument is passed. */
|
|
69
|
+
defaultSite: string;
|
|
70
|
+
/** Author name for new blog posts' `author:` frontmatter field (optional). */
|
|
71
|
+
author?: string;
|
|
72
|
+
/**
|
|
73
|
+
* Review journal directory relative to the project root. Defaults to
|
|
74
|
+
* `.deskwork/review-journal`. Host projects migrating from a prior layout
|
|
75
|
+
* can point this at an existing directory (e.g. `journal/editorial`).
|
|
76
|
+
*/
|
|
77
|
+
reviewJournalDir?: string;
|
|
78
|
+
}
|
|
79
|
+
/** Return the absolute path to `.deskwork/config.json` under a project root. */
|
|
80
|
+
export declare function configPath(projectRoot: string): string;
|
|
81
|
+
/**
|
|
82
|
+
* Validate and normalize an unknown value as a DeskworkConfig.
|
|
83
|
+
*
|
|
84
|
+
* Throws an Error with a specific message when the value doesn't match the
|
|
85
|
+
* schema. On success, returns a fresh typed object — callers can mutate it
|
|
86
|
+
* without worrying about shared references.
|
|
87
|
+
*/
|
|
88
|
+
export declare function parseConfig(value: unknown): DeskworkConfig;
|
|
89
|
+
/** Read and parse the deskwork config for a project root. */
|
|
90
|
+
export declare function readConfig(projectRoot: string): DeskworkConfig;
|
|
91
|
+
//# sourceMappingURL=config.d.ts.map
|