@cyber-dash-tech/revela 0.18.15 → 0.19.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/README.md +48 -45
- package/README.zh-CN.md +48 -45
- package/assets/img/lucent-01.jpg +0 -0
- package/assets/img/lucent-02.jpg +0 -0
- package/assets/img/lucent-03.jpg +0 -0
- package/assets/img/lucent-dark-01.jpg +0 -0
- package/assets/img/lucent-dark-02.jpg +0 -0
- package/assets/img/lucent-dark-03.jpg +0 -0
- package/assets/img/monet-01.jpg +0 -0
- package/assets/img/monet-02.jpg +0 -0
- package/assets/img/monet-03.jpg +0 -0
- package/assets/img/starter-01.jpg +0 -0
- package/assets/img/starter-02.jpg +0 -0
- package/assets/img/starter-03.jpg +0 -0
- package/assets/img/summit-01.jpg +0 -0
- package/assets/img/summit-02.jpg +0 -0
- package/assets/img/summit-03.jpg +0 -0
- package/designs/lucent/DESIGN.md +108 -1
- package/designs/lucent/design.css +283 -0
- package/designs/lucent-dark/DESIGN.md +278 -0
- package/designs/lucent-dark/assets/card-lens.jpg +0 -0
- package/designs/lucent-dark/assets/closing-background.jpg +0 -0
- package/designs/lucent-dark/assets/cover-background.jpg +0 -0
- package/designs/lucent-dark/assets/report-visual.jpg +0 -0
- package/designs/lucent-dark/assets/soft-texture.jpg +0 -0
- package/designs/lucent-dark/assets/toc-orb.png +0 -0
- package/designs/lucent-dark/design.css +417 -0
- package/designs/monet/DESIGN.md +53 -9
- package/designs/monet/assets/card-lens.jpg +0 -0
- package/designs/monet/assets/closing-background.jpg +0 -0
- package/designs/monet/assets/cover-background.jpg +0 -0
- package/designs/monet/assets/report-visual.jpg +0 -0
- package/designs/monet/assets/soft-texture.jpg +0 -0
- package/designs/monet/assets/toc-orb.png +0 -0
- package/designs/monet/design.css +340 -0
- package/designs/starter/DESIGN.md +22 -5
- package/designs/starter/assets/card-lens.jpg +0 -0
- package/designs/starter/assets/closing-background.jpg +0 -0
- package/designs/starter/assets/cover-background.jpg +0 -0
- package/designs/starter/assets/report-visual.jpg +0 -0
- package/designs/starter/assets/soft-texture.jpg +0 -0
- package/designs/starter/assets/toc-orb.png +0 -0
- package/designs/starter/design.css +322 -0
- package/designs/summit/DESIGN.md +54 -9
- package/designs/summit/assets/card-lens.jpg +0 -0
- package/designs/summit/assets/closing-background.jpg +0 -0
- package/designs/summit/assets/cover-background.jpg +0 -0
- package/designs/summit/assets/report-visual.jpg +0 -0
- package/designs/summit/assets/soft-texture.jpg +0 -0
- package/designs/summit/assets/toc-orb.png +0 -0
- package/designs/summit/design.css +334 -0
- package/lib/commands/designs-new.ts +18 -21
- package/lib/commands/designs-preview.ts +3 -8
- package/lib/deck-html/foundation.ts +8 -8
- package/lib/design/designs.ts +385 -14
- package/lib/narrative-state/deck-plan-artifact.ts +40 -3
- package/lib/page-templates/built-in-preview.html +373 -0
- package/lib/page-templates/contracts.ts +2 -0
- package/lib/page-templates/css.ts +2 -0
- package/lib/page-templates/foundation.ts +41 -0
- package/lib/page-templates/index.ts +6 -0
- package/lib/page-templates/registry.ts +3 -0
- package/lib/page-templates/render.ts +1202 -0
- package/lib/page-templates/templates/agenda.ts +4 -0
- package/lib/page-templates/templates/chart-takeaways.ts +4 -0
- package/lib/page-templates/templates/claim-supporting-visual.ts +4 -0
- package/lib/page-templates/templates/closing.ts +4 -0
- package/lib/page-templates/templates/cover.ts +4 -0
- package/lib/page-templates/templates/executive-summary.ts +4 -0
- package/lib/page-templates/templates/index.ts +19 -0
- package/lib/page-templates/templates/key-message-evidence.ts +4 -0
- package/lib/page-templates/templates/metric-highlight.ts +4 -0
- package/lib/page-templates/templates/problem-context.ts +4 -0
- package/lib/page-templates/templates/process-steps.ts +4 -0
- package/lib/page-templates/templates/recommendation-decision.ts +4 -0
- package/lib/page-templates/templates/risks-tradeoffs.ts +4 -0
- package/lib/page-templates/templates/section-divider.ts +4 -0
- package/lib/page-templates/templates/shared.ts +11 -0
- package/lib/page-templates/templates/table-comparison.ts +4 -0
- package/lib/page-templates/templates/timeline-roadmap.ts +4 -0
- package/lib/page-templates/vocabulary.ts +158 -0
- package/lib/prompt-builder.ts +9 -5
- package/lib/qa/artifact.ts +117 -7
- package/lib/qa/checks.ts +1 -1
- package/lib/qa/compliance.ts +5 -1
- package/lib/qa/component-contracts.ts +90 -0
- package/lib/runtime/index.ts +99 -3
- package/package.json +7 -15
- package/plugins/revela/.codex-plugin/plugin.json +4 -4
- package/plugins/revela/hooks/revela_guard.ts +35 -0
- package/plugins/revela/hooks/revela_post_write_notice.ts +39 -9
- package/plugins/revela/mcp/revela-server.ts +103 -7
- package/plugins/revela/skills/revela/SKILL.md +3 -3
- package/plugins/revela/skills/revela-design/SKILL.md +25 -14
- package/plugins/revela/skills/revela-helper/SKILL.md +3 -3
- package/plugins/revela/skills/revela-make-deck/SKILL.md +27 -12
- package/plugins/revela/skills/revela-research/SKILL.md +1 -0
- package/skill/SKILL.md +11 -2
- package/designs/lucent/preview.html +0 -612
- package/designs/monet/preview.html +0 -2293
- package/designs/starter/preview.html +0 -314
- package/designs/summit/preview.html +0 -2284
- package/plugins/revela/skills/revela-review/SKILL.md +0 -46
package/lib/runtime/index.ts
CHANGED
|
@@ -15,6 +15,7 @@ import {
|
|
|
15
15
|
installDesignDraftPackage,
|
|
16
16
|
listDesignAssets,
|
|
17
17
|
listDesigns,
|
|
18
|
+
materializeDesignPreview,
|
|
18
19
|
packDesignPackage,
|
|
19
20
|
seedBuiltinDesigns,
|
|
20
21
|
validateDesignDraftPackage,
|
|
@@ -30,6 +31,7 @@ import { runNarrativeMarkdownQa, type MarkdownQaOptions } from "../narrative-vau
|
|
|
30
31
|
import { formatArtifactQaUserNotice, formatMarkdownQaUserNotice } from "../hook-notifications"
|
|
31
32
|
import { deckPlanDesignDiagnostics, readDeckPlanArtifact, upsertDeckPlanSlideArtifact, type DeckPlanSlideUpsertInput } from "../narrative-state/deck-plan-artifact"
|
|
32
33
|
import { extractDesignClasses } from "../design/designs"
|
|
34
|
+
import { addTemplateScaffold as addPageTemplateScaffold, addTemplateSlide as addPageTemplateSlide, getPageTemplateFoundation, getPageTemplateVocabulary, listPageTemplates as listBuiltinPageTemplates, renderTemplateScaffold as renderPageTemplateScaffold, renderTemplateSlide as renderPageTemplateSlide } from "../page-templates"
|
|
33
35
|
import { recordRenderedArtifact, workspaceRelative } from "../workspace-state/rendered-artifacts"
|
|
34
36
|
import { existingWorkspaceMetaPath, workspaceMetaPath } from "../workspace-meta"
|
|
35
37
|
import { checkMaterialIntake, extractMaterial, materialIntakeNoticeForCommand, prepareLocalMaterials, recordMaterialReview } from "../material-intake"
|
|
@@ -84,17 +86,49 @@ export interface RuntimeDeckPlanSlideUpsertInput extends RuntimeWorkspaceInput,
|
|
|
84
86
|
designName?: string
|
|
85
87
|
}
|
|
86
88
|
|
|
89
|
+
export interface RuntimeTemplateSlideInput extends RuntimeWorkspaceInput {
|
|
90
|
+
templateId: string
|
|
91
|
+
slideIndex: number
|
|
92
|
+
content: Record<string, any>
|
|
93
|
+
designName?: string
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
export interface RuntimeTemplateSlideAddInput extends RuntimeTemplateSlideInput {
|
|
97
|
+
outputPath: string
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
export interface RuntimeTemplateScaffoldInput extends RuntimeWorkspaceInput {
|
|
101
|
+
templateId: string
|
|
102
|
+
slideIndex: number
|
|
103
|
+
seed?: Record<string, any>
|
|
104
|
+
designName?: string
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
export interface RuntimeTemplateScaffoldAddInput extends RuntimeTemplateScaffoldInput {
|
|
108
|
+
outputPath: string
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
export interface RuntimePageTemplateReadInput {
|
|
112
|
+
templateId: string
|
|
113
|
+
}
|
|
114
|
+
|
|
87
115
|
export interface RuntimeDesignCreateInput {
|
|
88
116
|
name: string
|
|
89
117
|
base?: string
|
|
90
118
|
designMd: string
|
|
91
|
-
|
|
119
|
+
designCss?: string
|
|
120
|
+
previewHtml?: string
|
|
92
121
|
assets?: DesignPackageAssetInput[]
|
|
93
122
|
overwrite?: boolean
|
|
94
123
|
}
|
|
95
124
|
|
|
96
125
|
export interface RuntimeDesignDraftCreateInput extends RuntimeDesignCreateInput, RuntimeWorkspaceInput {}
|
|
97
126
|
|
|
127
|
+
export interface RuntimeDesignPreviewInput extends RuntimeWorkspaceInput {
|
|
128
|
+
name: string
|
|
129
|
+
source?: "draft" | "installed" | "builtin"
|
|
130
|
+
}
|
|
131
|
+
|
|
98
132
|
export interface RuntimeDomainCreateInput {
|
|
99
133
|
name: string
|
|
100
134
|
domainMd: string
|
|
@@ -218,6 +252,58 @@ export function createDeckFoundation(input: RuntimeDeckFoundationInput) {
|
|
|
218
252
|
})
|
|
219
253
|
}
|
|
220
254
|
|
|
255
|
+
export function listPageTemplates() {
|
|
256
|
+
return listBuiltinPageTemplates()
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
export function renderTemplateSlide(input: RuntimeTemplateSlideInput) {
|
|
260
|
+
return renderPageTemplateSlide({
|
|
261
|
+
templateId: requiredString(input?.templateId, "templateId"),
|
|
262
|
+
slideIndex: input.slideIndex,
|
|
263
|
+
content: input.content ?? {},
|
|
264
|
+
designName: input.designName || activeDesign(),
|
|
265
|
+
})
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
export function renderTemplateScaffold(input: RuntimeTemplateScaffoldInput) {
|
|
269
|
+
return renderPageTemplateScaffold({
|
|
270
|
+
templateId: requiredString(input?.templateId, "templateId"),
|
|
271
|
+
slideIndex: input.slideIndex,
|
|
272
|
+
seed: input.seed ?? {},
|
|
273
|
+
designName: input.designName || activeDesign(),
|
|
274
|
+
})
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
export function addTemplateSlide(input: RuntimeTemplateSlideAddInput) {
|
|
278
|
+
return addPageTemplateSlide({
|
|
279
|
+
workspaceRoot: root(input.workspaceRoot),
|
|
280
|
+
outputPath: requiredString(input?.outputPath, "outputPath"),
|
|
281
|
+
templateId: requiredString(input?.templateId, "templateId"),
|
|
282
|
+
slideIndex: input.slideIndex,
|
|
283
|
+
content: input.content ?? {},
|
|
284
|
+
designName: input.designName || activeDesign(),
|
|
285
|
+
})
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
export function addTemplateScaffold(input: RuntimeTemplateScaffoldAddInput) {
|
|
289
|
+
return addPageTemplateScaffold({
|
|
290
|
+
workspaceRoot: root(input.workspaceRoot),
|
|
291
|
+
outputPath: requiredString(input?.outputPath, "outputPath"),
|
|
292
|
+
templateId: requiredString(input?.templateId, "templateId"),
|
|
293
|
+
slideIndex: input.slideIndex,
|
|
294
|
+
seed: input.seed ?? {},
|
|
295
|
+
designName: input.designName || activeDesign(),
|
|
296
|
+
})
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
export function pageTemplateFoundation(input: RuntimePageTemplateReadInput) {
|
|
300
|
+
return { ok: true, foundation: getPageTemplateFoundation(requiredString(input?.templateId, "templateId")) }
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
export function pageTemplateVocabulary(input: RuntimePageTemplateReadInput) {
|
|
304
|
+
return { ok: true, vocabulary: getPageTemplateVocabulary(requiredString(input?.templateId, "templateId")) }
|
|
305
|
+
}
|
|
306
|
+
|
|
221
307
|
export async function runDeckQa(input: RuntimeFileInput) {
|
|
222
308
|
const { formatArtifactQAReport, runArtifactQA } = await import("../qa/artifact")
|
|
223
309
|
const workspaceRoot = root(input.workspaceRoot)
|
|
@@ -362,7 +448,8 @@ export function designCreate(input: RuntimeDesignCreateInput) {
|
|
|
362
448
|
name: requiredString(input?.name, "design name"),
|
|
363
449
|
base: input.base,
|
|
364
450
|
designMd: requiredString(input?.designMd, "designMd"),
|
|
365
|
-
|
|
451
|
+
designCss: input.designCss,
|
|
452
|
+
previewHtml: input.previewHtml,
|
|
366
453
|
assets: input.assets,
|
|
367
454
|
overwrite: input.overwrite ?? false,
|
|
368
455
|
})
|
|
@@ -378,7 +465,8 @@ export function designDraftCreate(input: RuntimeDesignDraftCreateInput) {
|
|
|
378
465
|
name: requiredString(input?.name, "design name"),
|
|
379
466
|
base: input.base,
|
|
380
467
|
designMd: requiredString(input?.designMd, "designMd"),
|
|
381
|
-
|
|
468
|
+
designCss: input.designCss,
|
|
469
|
+
previewHtml: input.previewHtml,
|
|
382
470
|
assets: input.assets,
|
|
383
471
|
overwrite: input.overwrite ?? false,
|
|
384
472
|
})
|
|
@@ -388,6 +476,14 @@ export function designDraftValidate(input: RuntimeWorkspaceInput & RuntimeNameIn
|
|
|
388
476
|
return validateDesignDraftPackage(root(input.workspaceRoot), requiredName(input, "design draft"))
|
|
389
477
|
}
|
|
390
478
|
|
|
479
|
+
export function designPreview(input: RuntimeDesignPreviewInput) {
|
|
480
|
+
return materializeDesignPreview({
|
|
481
|
+
workspaceRoot: root(input.workspaceRoot),
|
|
482
|
+
name: requiredName(input, "design"),
|
|
483
|
+
source: input.source,
|
|
484
|
+
})
|
|
485
|
+
}
|
|
486
|
+
|
|
391
487
|
export function designDraftInstall(input: RuntimeDraftInstallInput) {
|
|
392
488
|
seedBuiltinDesigns()
|
|
393
489
|
return installDesignDraftPackage({
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cyber-dash-tech/revela",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.19.0",
|
|
4
4
|
"description": "Codex-first CLI/MCP workspace for trusted narrative artifacts from local sources, research, and evidence",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./index.ts",
|
|
@@ -11,11 +11,7 @@
|
|
|
11
11
|
".": "./index.ts"
|
|
12
12
|
},
|
|
13
13
|
"files": [
|
|
14
|
-
"assets/img/
|
|
15
|
-
"assets/img/logo-64.png",
|
|
16
|
-
"assets/img/logo-256.png",
|
|
17
|
-
"assets/img/logo-wordmark.png",
|
|
18
|
-
"assets/img/review-ui.png",
|
|
14
|
+
"assets/img/",
|
|
19
15
|
"bin/",
|
|
20
16
|
"plugin.ts",
|
|
21
17
|
"lib/",
|
|
@@ -23,15 +19,11 @@
|
|
|
23
19
|
"tools/",
|
|
24
20
|
"skill/",
|
|
25
21
|
"designs/aurora/DESIGN.md",
|
|
26
|
-
"designs/starter/
|
|
27
|
-
"designs/
|
|
28
|
-
"designs/
|
|
29
|
-
"designs/
|
|
30
|
-
"designs/
|
|
31
|
-
"designs/monet/preview.html",
|
|
32
|
-
"designs/lucent/DESIGN.md",
|
|
33
|
-
"designs/lucent/preview.html",
|
|
34
|
-
"designs/lucent/assets/",
|
|
22
|
+
"designs/starter/",
|
|
23
|
+
"designs/summit/",
|
|
24
|
+
"designs/monet/",
|
|
25
|
+
"designs/lucent/",
|
|
26
|
+
"designs/lucent-dark/",
|
|
35
27
|
"domains/general/INDUSTRY.md",
|
|
36
28
|
"domains/deeptech-investment/INDUSTRY.md",
|
|
37
29
|
"domains/consulting/INDUSTRY.md",
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "revela",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "Use Revela in Codex to specify, research, plan, make,
|
|
3
|
+
"version": "0.19.0",
|
|
4
|
+
"description": "Use Revela in Codex to specify, research, plan, make, and export trusted narrative decision artifacts.",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "cyber-dash-tech",
|
|
7
7
|
"url": "https://github.com/cyber-dash-tech"
|
|
@@ -20,7 +20,7 @@
|
|
|
20
20
|
"interface": {
|
|
21
21
|
"displayName": "Revela",
|
|
22
22
|
"shortDescription": "Trusted narrative artifacts from local sources and research.",
|
|
23
|
-
"longDescription": "Revela helps Codex route workspace workflows, capture requirements in spec.md, ingest local materials, save research findings, plan decks, generate HTML deck artifacts,
|
|
23
|
+
"longDescription": "Revela helps Codex route workspace workflows, capture requirements in spec.md, ingest local materials, save research findings, plan decks, generate HTML deck artifacts, open them in Codex Browser for annotation, and export PDF/PPTX/PNG outputs while preserving source traceability.",
|
|
24
24
|
"developerName": "cyber-dash-tech",
|
|
25
25
|
"category": "Productivity",
|
|
26
26
|
"capabilities": [
|
|
@@ -31,7 +31,7 @@
|
|
|
31
31
|
"Use Revela to route the next workflow step for this workspace.",
|
|
32
32
|
"Use Revela to write a spec.md for this deck objective.",
|
|
33
33
|
"Use Revela to make a deck from the deck plan.",
|
|
34
|
-
"Use Revela to
|
|
34
|
+
"Use Revela to export this deck artifact."
|
|
35
35
|
],
|
|
36
36
|
"brandColor": "#2563EB"
|
|
37
37
|
}
|
|
@@ -26,6 +26,16 @@ export async function runPreWriteChecks(input: string): Promise<HookResult> {
|
|
|
26
26
|
].join("\n"))
|
|
27
27
|
}
|
|
28
28
|
|
|
29
|
+
const protectedDesignCssTargets = extractProtectedDesignCssPatchTargets(input)
|
|
30
|
+
if (protectedDesignCssTargets.length > 0) {
|
|
31
|
+
messages.push([
|
|
32
|
+
"Revela design CSS patches are blocked outside the design draft workflow.",
|
|
33
|
+
`Protected target(s): ${protectedDesignCssTargets.map((target) => `\`${target}\``).join(", ")}`,
|
|
34
|
+
"Create or edit designs under `.revela/drafts/designs/<name>/design.css`, then validate and install the draft.",
|
|
35
|
+
"Deck-local `decks/_revela-design/**/design.css` files are render snapshots and should be regenerated, not patched.",
|
|
36
|
+
].join("\n"))
|
|
37
|
+
}
|
|
38
|
+
|
|
29
39
|
const deckTargets = extractDeckHtmlPatchTargets(input)
|
|
30
40
|
if (deckTargets.length > 0) {
|
|
31
41
|
const pluginRoot = resolve(process.env.PLUGIN_ROOT || dirname(dirname(fileURLToPath(import.meta.url))))
|
|
@@ -74,6 +84,31 @@ export function extractNarrativeCachePatchTargets(input: string): string[] {
|
|
|
74
84
|
return [...targets].sort((a, b) => a.localeCompare(b))
|
|
75
85
|
}
|
|
76
86
|
|
|
87
|
+
export function extractProtectedDesignCssPatchTargets(input: string): string[] {
|
|
88
|
+
const targets = new Set<string>()
|
|
89
|
+
for (const patch of patchPayloads(input)) {
|
|
90
|
+
const pattern = /(?:^\*\*\* Update File: |^\*\*\* Add File: |^\*\*\* Delete File: |^\*\*\* Move to: )([^\r\n]*design\.css)\s*$/gm
|
|
91
|
+
let match: RegExpExecArray | null
|
|
92
|
+
while ((match = pattern.exec(patch))) {
|
|
93
|
+
const target = match[1].trim().replace(/\\/g, "/")
|
|
94
|
+
if (isAllowedDesignDraftCssTarget(target)) continue
|
|
95
|
+
if (isProtectedDesignCssTarget(target)) targets.add(target)
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
return [...targets].sort((a, b) => a.localeCompare(b))
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
function isAllowedDesignDraftCssTarget(target: string): boolean {
|
|
102
|
+
return /(^|\/)\.revela\/drafts\/designs\/[^/]+\/design\.css$/.test(target)
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
function isProtectedDesignCssTarget(target: string): boolean {
|
|
106
|
+
return /(^|\/)designs\/[^/]+\/design\.css$/.test(target)
|
|
107
|
+
|| /(^|\/)decks\/_revela-design\/[^/]+\/design\.css$/.test(target)
|
|
108
|
+
|| /(^|\/)_revela-design\/[^/]+\/design\.css$/.test(target)
|
|
109
|
+
|| /(^|\/)\.config\/revela\/designs\/[^/]+\/design\.css$/.test(target)
|
|
110
|
+
}
|
|
111
|
+
|
|
77
112
|
function patchPayloads(input: string): string[] {
|
|
78
113
|
try {
|
|
79
114
|
const parsed = JSON.parse(input)
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import { dirname, resolve } from "path"
|
|
1
|
+
import { basename, dirname, resolve } from "path"
|
|
2
|
+
import { existsSync, readFileSync } from "fs"
|
|
2
3
|
import { fileURLToPath, pathToFileURL } from "url"
|
|
3
4
|
import { resolveRevelaRuntime } from "../mcp/runtime-resolver"
|
|
4
5
|
|
|
@@ -9,15 +10,13 @@ interface HookResult {
|
|
|
9
10
|
|
|
10
11
|
export function extractDeckHtmlTargets(input: string): string[] {
|
|
11
12
|
const targets = new Set<string>()
|
|
12
|
-
const
|
|
13
|
-
/\bdecks\/[^\s"'`<>]+\.html\b/g,
|
|
14
|
-
/(?:^\*\*\* Update File: |^\*\*\* Add File: )([^\r\n]+decks\/[^\r\n]+\.html)\s*$/gm,
|
|
15
|
-
]
|
|
13
|
+
const pattern = /(?:^\*\*\* Update File: |^\*\*\* Add File: )((?:[^\r\n]*\/)?decks\/[^\s"'`<>*?\r\n]+\.html)\s*$/gm
|
|
16
14
|
|
|
17
|
-
for (const
|
|
15
|
+
for (const patch of patchPayloadsFromInput(input)) {
|
|
18
16
|
let match: RegExpExecArray | null
|
|
19
|
-
while ((match = pattern.exec(
|
|
20
|
-
|
|
17
|
+
while ((match = pattern.exec(patch))) {
|
|
18
|
+
const target = match[1].trim()
|
|
19
|
+
if (!target.includes("*") && !target.includes("?")) targets.add(target)
|
|
21
20
|
}
|
|
22
21
|
}
|
|
23
22
|
|
|
@@ -59,6 +58,32 @@ export function workspaceRootFromInput(input: string): string {
|
|
|
59
58
|
return resolve(process.env.CODEX_WORKSPACE_ROOT || process.env.PWD || process.cwd())
|
|
60
59
|
}
|
|
61
60
|
|
|
61
|
+
function titleFromDeckHtml(absolutePath: string): string {
|
|
62
|
+
try {
|
|
63
|
+
if (!existsSync(absolutePath)) return basename(absolutePath)
|
|
64
|
+
const html = readFileSync(absolutePath, "utf-8")
|
|
65
|
+
const title = html.match(/<title[^>]*>([^<]+)<\/title>/i)?.[1]?.trim()
|
|
66
|
+
return title || basename(absolutePath)
|
|
67
|
+
} catch {
|
|
68
|
+
return basename(absolutePath)
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
export function formatDeckWebsiteCardHandoffNotice(workspaceRoot: string, target: string): string {
|
|
73
|
+
const absolutePath = resolve(workspaceRoot, target)
|
|
74
|
+
const deckUrl = pathToFileURL(absolutePath).href
|
|
75
|
+
const title = titleFromDeckHtml(absolutePath)
|
|
76
|
+
return [
|
|
77
|
+
"**Deck website card ready**",
|
|
78
|
+
"",
|
|
79
|
+
`Artifact QA passed for \`${target}\`. Reply with this standalone deck link so Codex renders an Open in Browser website card:`,
|
|
80
|
+
"",
|
|
81
|
+
`[${title}](${deckUrl})`,
|
|
82
|
+
"",
|
|
83
|
+
`If the card or direct \`file://\` navigation is unavailable, start a read-only local static server from the workspace root and link to \`http://127.0.0.1:<port>/${target}\` instead.`,
|
|
84
|
+
].join("\n")
|
|
85
|
+
}
|
|
86
|
+
|
|
62
87
|
export async function runPostWriteChecks(input: string): Promise<HookResult> {
|
|
63
88
|
const messages: string[] = []
|
|
64
89
|
const deckTargets = extractDeckHtmlTargets(input)
|
|
@@ -97,11 +122,16 @@ export async function runPostWriteChecks(input: string): Promise<HookResult> {
|
|
|
97
122
|
}
|
|
98
123
|
|
|
99
124
|
for (const target of deckTargets) {
|
|
125
|
+
if (!existsSync(resolve(workspaceRoot, target))) continue
|
|
100
126
|
const result = await runtimeModule.runDeckQa({ workspaceRoot, file: target })
|
|
101
127
|
messages.push(result.markdown ?? JSON.stringify(result, null, 2))
|
|
102
128
|
const notice = runtimeModule.formatArtifactQaUserNotice?.(result.report)
|
|
103
129
|
if (notice) messages.push(notice)
|
|
104
|
-
if (
|
|
130
|
+
if (result.ok) {
|
|
131
|
+
messages.push(formatDeckWebsiteCardHandoffNotice(workspaceRoot, target))
|
|
132
|
+
} else {
|
|
133
|
+
ok = false
|
|
134
|
+
}
|
|
105
135
|
}
|
|
106
136
|
|
|
107
137
|
return { ok, messages }
|
|
@@ -13,6 +13,13 @@ type RuntimeModule = {
|
|
|
13
13
|
readDeckPlan(input?: any): any
|
|
14
14
|
upsertDeckPlanSlide(input: any): any
|
|
15
15
|
createDeckFoundation(input: any): any
|
|
16
|
+
listPageTemplates(): any
|
|
17
|
+
renderTemplateSlide(input: any): any
|
|
18
|
+
addTemplateSlide(input: any): any
|
|
19
|
+
renderTemplateScaffold(input: any): any
|
|
20
|
+
addTemplateScaffold(input: any): any
|
|
21
|
+
pageTemplateFoundation(input: any): any
|
|
22
|
+
pageTemplateVocabulary(input: any): any
|
|
16
23
|
runDeckQa(input: any): Promise<any>
|
|
17
24
|
exportPdf(input: any): Promise<any>
|
|
18
25
|
exportPptx(input: any): Promise<any>
|
|
@@ -25,6 +32,7 @@ type RuntimeModule = {
|
|
|
25
32
|
designActivate(input: any): any
|
|
26
33
|
designCreate(input: any): any
|
|
27
34
|
designValidate(input: any): any
|
|
35
|
+
designPreview(input: any): any
|
|
28
36
|
designDraftCreate(input: any): any
|
|
29
37
|
designDraftValidate(input: any): any
|
|
30
38
|
designDraftInstall(input: any): any
|
|
@@ -94,6 +102,71 @@ const tools = [
|
|
|
94
102
|
overwrite: booleanProp("Whether create mode may overwrite an existing file."),
|
|
95
103
|
}, ["outputPath", "title", "language"]),
|
|
96
104
|
},
|
|
105
|
+
{
|
|
106
|
+
name: "revela_list_page_templates",
|
|
107
|
+
description: "List built-in Revela page templates with semantic fields, content rules, and template QA contracts.",
|
|
108
|
+
inputSchema: objectSchema({}),
|
|
109
|
+
},
|
|
110
|
+
{
|
|
111
|
+
name: "revela_render_template_slide",
|
|
112
|
+
description: "Render one built-in page template into a stable Revela slide HTML skeleton using the active/requested design.",
|
|
113
|
+
inputSchema: objectSchema({
|
|
114
|
+
workspaceRoot: stringProp("Optional workspace root."),
|
|
115
|
+
designName: stringProp("Optional design name. Defaults to the active design."),
|
|
116
|
+
templateId: requiredStringProp("Built-in template id, such as timeline-roadmap."),
|
|
117
|
+
slideIndex: requiredNumberProp("Positive 1-based slide index."),
|
|
118
|
+
content: objectProp("Template content fields. The built-in template renderer owns the HTML skeleton."),
|
|
119
|
+
}, ["templateId", "slideIndex", "content"]),
|
|
120
|
+
},
|
|
121
|
+
{
|
|
122
|
+
name: "revela_page_template_foundation",
|
|
123
|
+
description: "Read the built-in template foundation for custom design authoring: scaffold HTML, CSS hooks, slots, and contract notes.",
|
|
124
|
+
inputSchema: objectSchema({
|
|
125
|
+
templateId: requiredStringProp("Built-in template id, such as timeline-roadmap."),
|
|
126
|
+
}, ["templateId"]),
|
|
127
|
+
},
|
|
128
|
+
{
|
|
129
|
+
name: "revela_page_template_vocabulary",
|
|
130
|
+
description: "Read machine-readable classes, slots, editable regions, replaceable regions, and contract notes for one page template.",
|
|
131
|
+
inputSchema: objectSchema({
|
|
132
|
+
templateId: requiredStringProp("Built-in template id, such as timeline-roadmap."),
|
|
133
|
+
}, ["templateId"]),
|
|
134
|
+
},
|
|
135
|
+
{
|
|
136
|
+
name: "revela_render_template_scaffold",
|
|
137
|
+
description: "Render one built-in page template scaffold with stable editable slots using minimal seed content.",
|
|
138
|
+
inputSchema: objectSchema({
|
|
139
|
+
workspaceRoot: stringProp("Optional workspace root."),
|
|
140
|
+
designName: stringProp("Optional design name. Defaults to the active design."),
|
|
141
|
+
templateId: requiredStringProp("Built-in template id, such as timeline-roadmap."),
|
|
142
|
+
slideIndex: requiredNumberProp("Positive 1-based slide index."),
|
|
143
|
+
seed: objectProp("Optional scaffold seed fields. This is not the final authoring interface."),
|
|
144
|
+
}, ["templateId", "slideIndex"]),
|
|
145
|
+
},
|
|
146
|
+
{
|
|
147
|
+
name: "revela_add_template_scaffold",
|
|
148
|
+
description: "Render and append one built-in page template scaffold into an existing Revela deck HTML file between slide markers.",
|
|
149
|
+
inputSchema: objectSchema({
|
|
150
|
+
workspaceRoot: stringProp("Optional workspace root."),
|
|
151
|
+
outputPath: requiredStringProp("Workspace-relative HTML deck path."),
|
|
152
|
+
designName: stringProp("Optional design name. Defaults to the active design."),
|
|
153
|
+
templateId: requiredStringProp("Built-in template id, such as timeline-roadmap."),
|
|
154
|
+
slideIndex: requiredNumberProp("Positive 1-based slide index."),
|
|
155
|
+
seed: objectProp("Optional scaffold seed fields. LLM should bounded-edit the inserted slide after scaffold creation."),
|
|
156
|
+
}, ["outputPath", "templateId", "slideIndex"]),
|
|
157
|
+
},
|
|
158
|
+
{
|
|
159
|
+
name: "revela_add_template_slide",
|
|
160
|
+
description: "Compatibility path: render and append one built-in page template slide from full content JSON into an existing deck HTML file.",
|
|
161
|
+
inputSchema: objectSchema({
|
|
162
|
+
workspaceRoot: stringProp("Optional workspace root."),
|
|
163
|
+
outputPath: requiredStringProp("Workspace-relative HTML deck path."),
|
|
164
|
+
designName: stringProp("Optional design name. Defaults to the active design."),
|
|
165
|
+
templateId: requiredStringProp("Built-in template id, such as timeline-roadmap."),
|
|
166
|
+
slideIndex: requiredNumberProp("Positive 1-based slide index."),
|
|
167
|
+
content: objectProp("Template content fields. Prefer scaffold-first flow for new deck creation."),
|
|
168
|
+
}, ["outputPath", "templateId", "slideIndex", "content"]),
|
|
169
|
+
},
|
|
97
170
|
{
|
|
98
171
|
name: "revela_run_deck_qa",
|
|
99
172
|
description: "Run Revela artifact QA on a generated HTML deck.",
|
|
@@ -171,15 +244,16 @@ const tools = [
|
|
|
171
244
|
},
|
|
172
245
|
{
|
|
173
246
|
name: "revela_design_create",
|
|
174
|
-
description: "Create and validate a local Revela design package from complete DESIGN.md and preview.html content.",
|
|
247
|
+
description: "Create and validate a local Revela design package from complete DESIGN.md, design.css, and optional legacy preview.html content.",
|
|
175
248
|
inputSchema: objectSchema({
|
|
176
249
|
name: requiredStringProp("Design name in kebab-case."),
|
|
177
250
|
base: stringProp("Optional base design used as structural scaffold."),
|
|
178
251
|
designMd: requiredStringProp("Complete DESIGN.md content."),
|
|
179
|
-
|
|
252
|
+
designCss: stringProp("Complete design.css content. Required for CSS-native designs; omitted only for legacy compatibility."),
|
|
253
|
+
previewHtml: stringProp("Optional legacy preview.html content. Current design previews are generated with revela_design_preview."),
|
|
180
254
|
assets: designAssetsProp(),
|
|
181
255
|
overwrite: booleanProp("Whether to replace an existing local design package. Defaults to false."),
|
|
182
|
-
}, ["name", "designMd"
|
|
256
|
+
}, ["name", "designMd"]),
|
|
183
257
|
},
|
|
184
258
|
{
|
|
185
259
|
name: "revela_design_validate",
|
|
@@ -194,10 +268,11 @@ const tools = [
|
|
|
194
268
|
name: requiredStringProp("Design name in kebab-case."),
|
|
195
269
|
base: stringProp("Optional base design used as structural scaffold."),
|
|
196
270
|
designMd: requiredStringProp("Complete DESIGN.md content."),
|
|
197
|
-
|
|
271
|
+
designCss: stringProp("Complete design.css content. Required for CSS-native designs; omitted only for legacy compatibility."),
|
|
272
|
+
previewHtml: stringProp("Optional legacy preview.html content. Current design previews are generated with revela_design_preview."),
|
|
198
273
|
assets: designAssetsProp(),
|
|
199
274
|
overwrite: booleanProp("Whether to replace an existing workspace draft. Defaults to false."),
|
|
200
|
-
}, ["name", "designMd"
|
|
275
|
+
}, ["name", "designMd"]),
|
|
201
276
|
},
|
|
202
277
|
{
|
|
203
278
|
name: "revela_design_draft_validate",
|
|
@@ -207,6 +282,15 @@ const tools = [
|
|
|
207
282
|
name: requiredStringProp("Design draft name to validate."),
|
|
208
283
|
}, ["name"]),
|
|
209
284
|
},
|
|
285
|
+
{
|
|
286
|
+
name: "revela_design_preview",
|
|
287
|
+
description: "Generate a workspace-local preview for a draft, installed, or built-in Revela design using the built-in page template preview fixture plus the design.css file.",
|
|
288
|
+
inputSchema: objectSchema({
|
|
289
|
+
workspaceRoot: stringProp("Optional workspace root."),
|
|
290
|
+
name: requiredStringProp("Design name to preview."),
|
|
291
|
+
source: stringProp("Optional source: draft, installed, or builtin. Defaults to draft when present, otherwise installed/builtin."),
|
|
292
|
+
}, ["name"]),
|
|
293
|
+
},
|
|
210
294
|
{
|
|
211
295
|
name: "revela_design_draft_install",
|
|
212
296
|
description: "Install a validated workspace-local Revela design draft into the user-level design registry.",
|
|
@@ -296,7 +380,7 @@ const tools = [
|
|
|
296
380
|
},
|
|
297
381
|
{
|
|
298
382
|
name: "revela_review_deck_read",
|
|
299
|
-
description: "
|
|
383
|
+
description: "Compatibility-only read of aggregate Review diagnostics for a Revela HTML deck: artifact QA, deck-plan diagnostics, and export/readiness signals.",
|
|
300
384
|
inputSchema: objectSchema({
|
|
301
385
|
workspaceRoot: stringProp("Optional workspace root."),
|
|
302
386
|
file: requiredStringProp("Workspace-relative or absolute HTML deck path."),
|
|
@@ -305,7 +389,7 @@ const tools = [
|
|
|
305
389
|
},
|
|
306
390
|
{
|
|
307
391
|
name: "revela_review_deck_open",
|
|
308
|
-
description: "
|
|
392
|
+
description: "Compatibility-only opener for the legacy local Codex-backed Review UI for a Revela HTML deck.",
|
|
309
393
|
inputSchema: objectSchema({
|
|
310
394
|
workspaceRoot: stringProp("Optional workspace root."),
|
|
311
395
|
file: requiredStringProp("Workspace-relative or absolute HTML deck path."),
|
|
@@ -421,6 +505,13 @@ async function callTool(name: string, args: any): Promise<any> {
|
|
|
421
505
|
if (name === "revela_read_deck_plan") return r.readDeckPlan(args)
|
|
422
506
|
if (name === "revela_upsert_deck_plan_slide") return r.upsertDeckPlanSlide(args)
|
|
423
507
|
if (name === "revela_create_deck_foundation") return r.createDeckFoundation(args)
|
|
508
|
+
if (name === "revela_list_page_templates") return r.listPageTemplates()
|
|
509
|
+
if (name === "revela_render_template_slide") return r.renderTemplateSlide(args)
|
|
510
|
+
if (name === "revela_add_template_slide") return r.addTemplateSlide(args)
|
|
511
|
+
if (name === "revela_page_template_foundation") return r.pageTemplateFoundation(args)
|
|
512
|
+
if (name === "revela_page_template_vocabulary") return r.pageTemplateVocabulary(args)
|
|
513
|
+
if (name === "revela_render_template_scaffold") return r.renderTemplateScaffold(args)
|
|
514
|
+
if (name === "revela_add_template_scaffold") return r.addTemplateScaffold(args)
|
|
424
515
|
if (name === "revela_run_deck_qa") return r.runDeckQa(args)
|
|
425
516
|
if (name === "revela_export_pdf") return r.exportPdf(args)
|
|
426
517
|
if (name === "revela_export_pptx") return r.exportPptx(args)
|
|
@@ -435,6 +526,7 @@ async function callTool(name: string, args: any): Promise<any> {
|
|
|
435
526
|
if (name === "revela_design_validate") return r.designValidate(args)
|
|
436
527
|
if (name === "revela_design_draft_create") return r.designDraftCreate(args)
|
|
437
528
|
if (name === "revela_design_draft_validate") return r.designDraftValidate(args)
|
|
529
|
+
if (name === "revela_design_preview") return r.designPreview(args)
|
|
438
530
|
if (name === "revela_design_draft_install") return r.designDraftInstall(args)
|
|
439
531
|
if (name === "revela_design_pack") return r.designPack(args)
|
|
440
532
|
if (name === "revela_design_install_archive") return r.designInstallArchive(args)
|
|
@@ -496,6 +588,10 @@ function arrayProp(description: string) {
|
|
|
496
588
|
return { type: "array", items: { type: "string" }, description }
|
|
497
589
|
}
|
|
498
590
|
|
|
591
|
+
function objectProp(description: string) {
|
|
592
|
+
return { type: "object", description, additionalProperties: true }
|
|
593
|
+
}
|
|
594
|
+
|
|
499
595
|
function stringOrArrayProp(description: string) {
|
|
500
596
|
return {
|
|
501
597
|
anyOf: [
|
|
@@ -11,7 +11,7 @@ Use this skill as the main Revela entrypoint in Codex. It should inspect intent
|
|
|
11
11
|
|
|
12
12
|
- This is a non-mutating router.
|
|
13
13
|
- It may inspect runtime, active design/domain, and workspace artifact status.
|
|
14
|
-
- It must not write `spec.md`, save research findings, write `deck-plan.md`, generate deck HTML, open
|
|
14
|
+
- It must not write `spec.md`, save research findings, write `deck-plan.md`, generate deck HTML, open deck browser views, or export artifacts.
|
|
15
15
|
- Route quickly once the next workflow is clear.
|
|
16
16
|
|
|
17
17
|
## Required Tools
|
|
@@ -29,7 +29,7 @@ Use this skill as the main Revela entrypoint in Codex. It should inspect intent
|
|
|
29
29
|
- `spec.md` exists but source support, material review, or findings are missing: use `revela-research`.
|
|
30
30
|
- `spec.md` and sufficient findings exist but `deck-plan.md` is missing or needs normal authoring: use `revela-research` Planning Handoff.
|
|
31
31
|
- Valid `deck-plan.md` exists and the user asks to make, generate, render, or update a deck: use `revela-make-deck`.
|
|
32
|
-
- Existing deck artifact and the user asks to review, diagnose, QA, or refine: use `revela-
|
|
32
|
+
- Existing deck artifact and the user asks to review, annotate, diagnose, QA, or refine: use Codex Browser's native browsing/annotation flow. If the deck was not just generated, reply with the existing deck as a website card/link and use native annotations after it opens; route export requests to `revela-export`.
|
|
33
33
|
- Existing deck artifact and the user asks for PDF, PPTX, or PNG output: use `revela-export`.
|
|
34
34
|
- If the next step is still ambiguous after inspection, ask the smallest missing question and recommend the safest next specialist skill.
|
|
35
35
|
|
|
@@ -47,5 +47,5 @@ Report:
|
|
|
47
47
|
- Do not write or patch files.
|
|
48
48
|
- Do not do external web research.
|
|
49
49
|
- Do not create or repair `spec.md` or `deck-plan.md`.
|
|
50
|
-
- Do not generate,
|
|
50
|
+
- Do not generate, annotate, patch, or export deck artifacts.
|
|
51
51
|
- Do not install or activate designs or domains; route those requests to `revela-design` or `revela-domain`.
|