@cyber-dash-tech/revela 0.9.0 → 0.10.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 +29 -4
- package/README.zh-CN.md +29 -4
- package/designs/monet/DESIGN.md +9 -9
- package/designs/starter/DESIGN.md +8 -8
- package/designs/summit/DESIGN.md +9 -9
- package/lib/commands/help.ts +2 -0
- package/lib/commands/inspect.ts +23 -0
- package/lib/commands/refine.ts +26 -0
- package/lib/commands/review.ts +8 -2
- package/lib/decks-state.ts +476 -6
- package/lib/inspect/open.ts +61 -0
- package/lib/inspect/prompt.ts +32 -0
- package/lib/inspect/request.ts +70 -0
- package/lib/inspect/requests.ts +86 -0
- package/lib/inspect/server.ts +1063 -0
- package/lib/inspect/slide-index.ts +12 -0
- package/lib/inspection-context/compile.ts +346 -0
- package/lib/inspection-context/match.ts +169 -0
- package/lib/inspection-context/project.ts +263 -0
- package/lib/inspection-context/result.ts +160 -0
- package/lib/refine/open.ts +68 -0
- package/lib/refine/server.ts +1581 -0
- package/package.json +1 -1
- package/plugin.ts +22 -0
- package/skill/SKILL.md +10 -5
- package/tools/decks.ts +12 -2
- package/tools/inspection-context.ts +22 -0
- package/tools/inspection-result.ts +63 -0
package/package.json
CHANGED
package/plugin.ts
CHANGED
|
@@ -46,6 +46,8 @@ import {
|
|
|
46
46
|
import { handlePdf } from "./lib/commands/pdf"
|
|
47
47
|
import { buildPptxNotesPrompt, handlePptx, parsePptxArgs, resolvePptxDeck } from "./lib/commands/pptx"
|
|
48
48
|
import { handleEdit } from "./lib/commands/edit"
|
|
49
|
+
import { handleInspect } from "./lib/commands/inspect"
|
|
50
|
+
import { handleRefine } from "./lib/commands/refine"
|
|
49
51
|
import { ensureEditableDeckOpenForChange } from "./lib/edit/open"
|
|
50
52
|
import { hasLiveEditorSessionForFile } from "./lib/edit/server"
|
|
51
53
|
import { handleDesignsPreview } from "./lib/commands/designs-preview"
|
|
@@ -80,6 +82,8 @@ import mediaBatchSaveTool from "./tools/media-batch-save"
|
|
|
80
82
|
import mediaSaveTool from "./tools/media-save"
|
|
81
83
|
import researchImagesListTool from "./tools/research-images-list"
|
|
82
84
|
import researchSaveTool from "./tools/research-save"
|
|
85
|
+
import inspectionContextTool from "./tools/inspection-context"
|
|
86
|
+
import inspectionResultTool from "./tools/inspection-result"
|
|
83
87
|
import workspaceScanTool from "./tools/workspace-scan"
|
|
84
88
|
import extractDocumentMaterialsTool from "./tools/extract-document-materials"
|
|
85
89
|
import qaTool from "./tools/qa"
|
|
@@ -332,6 +336,14 @@ const server: Plugin = (async (pluginCtx) => {
|
|
|
332
336
|
} as any)
|
|
333
337
|
return
|
|
334
338
|
}
|
|
339
|
+
if (sub === "refine") {
|
|
340
|
+
if (param) {
|
|
341
|
+
await send("`/revela refine` does not accept a target. It opens the only HTML deck in `decks/`.")
|
|
342
|
+
throw new Error("__REVELA_REFINE_USAGE_HANDLED__")
|
|
343
|
+
}
|
|
344
|
+
await handleRefine({ client, sessionID, workspaceRoot }, send)
|
|
345
|
+
throw new Error("__REVELA_REFINE_HANDLED__")
|
|
346
|
+
}
|
|
335
347
|
if (sub === "edit") {
|
|
336
348
|
if (param) {
|
|
337
349
|
await send("`/revela edit` no longer accepts a target. It opens the only HTML deck in `decks/`.")
|
|
@@ -340,6 +352,14 @@ const server: Plugin = (async (pluginCtx) => {
|
|
|
340
352
|
await handleEdit({ client, sessionID, workspaceRoot }, send)
|
|
341
353
|
throw new Error("__REVELA_EDIT_HANDLED__")
|
|
342
354
|
}
|
|
355
|
+
if (sub === "inspect") {
|
|
356
|
+
if (param) {
|
|
357
|
+
await send("`/revela inspect` does not accept a target. It opens the only HTML deck in `decks/`.")
|
|
358
|
+
throw new Error("__REVELA_INSPECT_USAGE_HANDLED__")
|
|
359
|
+
}
|
|
360
|
+
await handleInspect({ client, sessionID, workspaceRoot }, send)
|
|
361
|
+
throw new Error("__REVELA_INSPECT_HANDLED__")
|
|
362
|
+
}
|
|
343
363
|
if (sub === "designs" && !param) {
|
|
344
364
|
await handleDesignsList(send)
|
|
345
365
|
throw new Error("__REVELA_DESIGNS_LIST_HANDLED__")
|
|
@@ -438,6 +458,8 @@ const server: Plugin = (async (pluginCtx) => {
|
|
|
438
458
|
"revela-media-save": mediaSaveTool,
|
|
439
459
|
"revela-research-images-list": researchImagesListTool,
|
|
440
460
|
"revela-research-save": researchSaveTool,
|
|
461
|
+
"revela-inspection-context": inspectionContextTool,
|
|
462
|
+
"revela-inspection-result": inspectionResultTool,
|
|
441
463
|
"revela-workspace-scan": workspaceScanTool,
|
|
442
464
|
"revela-extract-document-materials": extractDocumentMaterialsTool,
|
|
443
465
|
"revela-qa": qaTool,
|
package/skill/SKILL.md
CHANGED
|
@@ -261,12 +261,17 @@ A 6-slide deck might be: Cover → Background → Content × 3 → Closing.
|
|
|
261
261
|
An 8-slide deck might be: Cover → TOC → Background → Content × 3 → Summary → Closing.
|
|
262
262
|
Never skip Cover, Background, or Closing regardless of deck length.
|
|
263
263
|
|
|
264
|
-
**Every `<section class="slide">` must include
|
|
265
|
-
`slide-qa="true"` for content-heavy layouts
|
|
266
|
-
QA column of the active design). Set
|
|
267
|
-
layouts (cover, TOC, closing, quote,
|
|
264
|
+
**Every `<section class="slide">` must include `slide-qa` and
|
|
265
|
+
`data-slide-index` attributes.** Set `slide-qa="true"` for content-heavy layouts
|
|
266
|
+
(those marked ✓ in the Layout Index QA column of the active design). Set
|
|
267
|
+
`slide-qa="false"` for structural or sparse layouts (cover, TOC, closing, quote,
|
|
268
|
+
summary, etc.). When unsure, use `"false"`.
|
|
268
269
|
|
|
269
|
-
|
|
270
|
+
`data-slide-index` is the canonical 1-based slide identity. It must match the
|
|
271
|
+
corresponding `DECKS.json` `slides[].index` value. Do not use 0-based
|
|
272
|
+
`data-index` as slide identity.
|
|
273
|
+
|
|
274
|
+
Example: `<section class="slide" slide-qa="true" data-slide-index="1">`
|
|
270
275
|
|
|
271
276
|
The export QA path treats this as deck metadata. It is consumed when PDF/PPTX
|
|
272
277
|
export runs preflight checks.
|
package/tools/decks.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { tool } from "@opencode-ai/plugin"
|
|
2
2
|
import {
|
|
3
|
+
applyEvidenceCandidates,
|
|
3
4
|
createDeckSpec,
|
|
4
5
|
DECKS_STATE_FILE,
|
|
5
6
|
normalizeWorkspaceDeckState,
|
|
@@ -25,7 +26,7 @@ export default tool({
|
|
|
25
26
|
"It stores active deck specs, per-slide content/layout/components, and computes write readiness.",
|
|
26
27
|
args: {
|
|
27
28
|
action: tool.schema
|
|
28
|
-
.enum(["read", "init", "upsertDeck", "upsertSlides", "review", "remember"])
|
|
29
|
+
.enum(["read", "init", "upsertDeck", "upsertSlides", "review", "applyEvidenceCandidates", "remember"])
|
|
29
30
|
.describe("Action to perform on DECKS.json."),
|
|
30
31
|
summary: tool.schema.boolean().optional().describe("For read: return a compact summary instead of full state."),
|
|
31
32
|
goal: tool.schema.string().optional().describe("For upsertDeck: deck goal."),
|
|
@@ -116,6 +117,7 @@ export default tool({
|
|
|
116
117
|
status: tool.schema.enum(["planned", "ready", "written", "qa_passed", "qa_failed"]).optional().describe("Slide production status."),
|
|
117
118
|
notes: tool.schema.string().optional().describe("Implementation notes for this slide."),
|
|
118
119
|
})).optional().describe("For upsertSlides: complete or partial slide specs."),
|
|
120
|
+
candidateIds: tool.schema.array(tool.schema.string()).optional().describe("For applyEvidenceCandidates: candidate IDs returned by revela-decks review to explicitly bind proposed evidenceDraft records into slide evidence."),
|
|
119
121
|
},
|
|
120
122
|
async execute(args, context) {
|
|
121
123
|
try {
|
|
@@ -175,11 +177,19 @@ export default tool({
|
|
|
175
177
|
}
|
|
176
178
|
|
|
177
179
|
if (args.action === "review") {
|
|
178
|
-
const reviewed = reviewDeckState(state)
|
|
180
|
+
const reviewed = reviewDeckState(state, undefined, { workspaceRoot })
|
|
179
181
|
writeDecksState(workspaceRoot, reviewed.state)
|
|
180
182
|
return JSON.stringify({ ok: true, path: DECKS_STATE_FILE, result: reviewed.result }, null, 2)
|
|
181
183
|
}
|
|
182
184
|
|
|
185
|
+
if (args.action === "applyEvidenceCandidates") {
|
|
186
|
+
const candidateIds = args.candidateIds ?? []
|
|
187
|
+
if (candidateIds.length === 0) return JSON.stringify({ ok: false, error: "candidateIds are required for applyEvidenceCandidates" })
|
|
188
|
+
const applied = applyEvidenceCandidates(state, candidateIds, { workspaceRoot })
|
|
189
|
+
writeDecksState(workspaceRoot, applied.state)
|
|
190
|
+
return JSON.stringify({ ok: true, path: DECKS_STATE_FILE, result: applied.result }, null, 2)
|
|
191
|
+
}
|
|
192
|
+
|
|
183
193
|
if (args.action === "remember") {
|
|
184
194
|
const memory = args.memory?.trim()
|
|
185
195
|
if (!memory) return JSON.stringify({ ok: false, error: "memory is required for remember" })
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { tool } from "@opencode-ai/plugin"
|
|
2
|
+
import { compileInspectionContext } from "../lib/inspection-context/compile"
|
|
3
|
+
import { normalizeWorkspaceDeckState, readOrCreateDecksState } from "../lib/decks-state"
|
|
4
|
+
|
|
5
|
+
export default tool({
|
|
6
|
+
description:
|
|
7
|
+
"Compile Revela's current DECKS.json into structured inspection context for debugging and future Evidence Inspector flows. " +
|
|
8
|
+
"This is read-only: it does not write artifacts, mutate DECKS.json, or generate user-facing files.",
|
|
9
|
+
args: {
|
|
10
|
+
slug: tool.schema.string().optional().describe("Optional deck slug to compile. Defaults to the active workspace deck."),
|
|
11
|
+
},
|
|
12
|
+
async execute(args, context) {
|
|
13
|
+
try {
|
|
14
|
+
const workspaceRoot = context.directory ?? process.cwd()
|
|
15
|
+
const state = normalizeWorkspaceDeckState(readOrCreateDecksState(workspaceRoot), workspaceRoot)
|
|
16
|
+
const inspectionContext = compileInspectionContext(state, args.slug)
|
|
17
|
+
return JSON.stringify({ ok: true, inspectionContext }, null, 2)
|
|
18
|
+
} catch (e: any) {
|
|
19
|
+
return JSON.stringify({ ok: false, error: e.message || String(e) })
|
|
20
|
+
}
|
|
21
|
+
},
|
|
22
|
+
})
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { tool } from "@opencode-ai/plugin"
|
|
2
|
+
import { completeInspectRequest } from "../lib/inspect/requests"
|
|
3
|
+
import type { InspectionResult } from "../lib/inspection-context/result"
|
|
4
|
+
|
|
5
|
+
const evidenceSourceItemSchema = tool.schema.object({
|
|
6
|
+
source: tool.schema.string().describe("Human-readable source label."),
|
|
7
|
+
sourcePath: tool.schema.string().optional(),
|
|
8
|
+
findingsFile: tool.schema.string().optional(),
|
|
9
|
+
location: tool.schema.string().optional(),
|
|
10
|
+
page: tool.schema.string().optional(),
|
|
11
|
+
url: tool.schema.string().optional(),
|
|
12
|
+
quote: tool.schema.string().optional(),
|
|
13
|
+
caveat: tool.schema.string().optional(),
|
|
14
|
+
})
|
|
15
|
+
|
|
16
|
+
export default tool({
|
|
17
|
+
description:
|
|
18
|
+
"Submit the final structured Evidence Inspector result for a pending /revela inspect request. " +
|
|
19
|
+
"Use only when responding to an inspection prompt. This updates the local browser inspector; it does not mutate DECKS.json or deck files.",
|
|
20
|
+
args: {
|
|
21
|
+
requestId: tool.schema.string().describe("Pending inspection request id from the inspection prompt."),
|
|
22
|
+
result: tool.schema.object({
|
|
23
|
+
version: tool.schema.number().describe("Must be 1."),
|
|
24
|
+
status: tool.schema.enum(["success", "no_match"]),
|
|
25
|
+
selectedText: tool.schema.string().optional(),
|
|
26
|
+
slide: tool.schema.object({
|
|
27
|
+
index: tool.schema.number(),
|
|
28
|
+
title: tool.schema.string(),
|
|
29
|
+
}).optional(),
|
|
30
|
+
matchConfidence: tool.schema.enum(["none", "low", "medium", "high"]),
|
|
31
|
+
cards: tool.schema.object({
|
|
32
|
+
purpose: tool.schema.object({
|
|
33
|
+
status: tool.schema.enum(["clear", "weak", "misplaced", "unknown"]),
|
|
34
|
+
role: tool.schema.string().optional(),
|
|
35
|
+
rationale: tool.schema.string(),
|
|
36
|
+
whyItMatters: tool.schema.string(),
|
|
37
|
+
}),
|
|
38
|
+
source: tool.schema.object({
|
|
39
|
+
status: tool.schema.enum(["supported", "weak", "unsupported", "not_needed", "unknown"]),
|
|
40
|
+
matchedClaim: tool.schema.string().optional(),
|
|
41
|
+
sources: tool.schema.array(evidenceSourceItemSchema),
|
|
42
|
+
warnings: tool.schema.array(tool.schema.string()),
|
|
43
|
+
gaps: tool.schema.array(tool.schema.string()),
|
|
44
|
+
caveats: tool.schema.array(tool.schema.string()),
|
|
45
|
+
rationale: tool.schema.string(),
|
|
46
|
+
}),
|
|
47
|
+
}),
|
|
48
|
+
stale: tool.schema.object({
|
|
49
|
+
stale: tool.schema.boolean(),
|
|
50
|
+
reason: tool.schema.string().optional(),
|
|
51
|
+
}).optional(),
|
|
52
|
+
}).describe("Final structured inspector result to render in the browser."),
|
|
53
|
+
},
|
|
54
|
+
async execute(args) {
|
|
55
|
+
try {
|
|
56
|
+
if (args.result.version !== 1) throw new Error("Inspection result version must be 1.")
|
|
57
|
+
const request = completeInspectRequest(args.requestId, args.result as InspectionResult)
|
|
58
|
+
return JSON.stringify({ ok: true, requestId: request.requestId, status: request.status })
|
|
59
|
+
} catch (e: any) {
|
|
60
|
+
return JSON.stringify({ ok: false, error: e.message || String(e) })
|
|
61
|
+
}
|
|
62
|
+
},
|
|
63
|
+
})
|