@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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cyber-dash-tech/revela",
3
- "version": "0.9.0",
3
+ "version": "0.10.0",
4
4
  "description": "OpenCode plugin that turns AI into an HTML slide deck generator",
5
5
  "type": "module",
6
6
  "main": "./index.ts",
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 a `slide-qa` attribute.** Set
265
- `slide-qa="true"` for content-heavy layouts (those marked ✓ in the Layout Index
266
- QA column of the active design). Set `slide-qa="false"` for structural or sparse
267
- layouts (cover, TOC, closing, quote, summary, etc.). When unsure, use `"false"`.
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
- Example: `<section class="slide" slide-qa="true" data-index="0">`
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
+ })