@cyber-dash-tech/revela 0.8.9 → 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/agents/narrative-reviewer-prompt.ts +143 -0
- 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 +18 -6
- package/lib/decks-state.ts +601 -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 +47 -2
- package/skill/SKILL.md +46 -8
- package/tools/decks.ts +23 -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"
|
|
@@ -87,6 +91,7 @@ import pdfTool from "./tools/pdf"
|
|
|
87
91
|
import pptxTool from "./tools/pptx"
|
|
88
92
|
import createEditTool from "./tools/edit"
|
|
89
93
|
import { RESEARCH_PROMPT, RESEARCH_AGENT_SIGNATURE } from "./lib/agents/research-prompt"
|
|
94
|
+
import { NARRATIVE_REVIEWER_PROMPT, NARRATIVE_REVIEWER_SIGNATURE } from "./lib/agents/narrative-reviewer-prompt"
|
|
90
95
|
import { formatReport, runComplianceQA } from "./lib/qa"
|
|
91
96
|
import { extractDesignClasses } from "./lib/design/designs"
|
|
92
97
|
import { log, childLog } from "./lib/log"
|
|
@@ -204,7 +209,7 @@ const server: Plugin = (async (pluginCtx) => {
|
|
|
204
209
|
}
|
|
205
210
|
|
|
206
211
|
return {
|
|
207
|
-
// ── Register /revela command +
|
|
212
|
+
// ── Register /revela command + Revela subagents ───────────────────────
|
|
208
213
|
config: async (opencodeConfig) => {
|
|
209
214
|
opencodeConfig.command ??= {}
|
|
210
215
|
opencodeConfig.command["revela"] = {
|
|
@@ -235,6 +240,24 @@ const server: Plugin = (async (pluginCtx) => {
|
|
|
235
240
|
// Give revela-research explicit websearch allow (overrides global deny below)
|
|
236
241
|
;(opencodeConfig.agent["revela-research"].permission as any).websearch = "allow"
|
|
237
242
|
|
|
243
|
+
// Register the read-only narrative reviewer subagent.
|
|
244
|
+
// It can inspect workspace state and referenced files, but cannot write or browse.
|
|
245
|
+
opencodeConfig.agent["revela-narrative-reviewer"] = {
|
|
246
|
+
description: "Revela narrative reviewer — read-only critique of narrative brief and slide-plan alignment",
|
|
247
|
+
mode: "subagent",
|
|
248
|
+
prompt: NARRATIVE_REVIEWER_PROMPT,
|
|
249
|
+
permission: {
|
|
250
|
+
edit: "deny",
|
|
251
|
+
bash: {
|
|
252
|
+
"*": "deny",
|
|
253
|
+
"ls *": "allow",
|
|
254
|
+
"ls": "allow",
|
|
255
|
+
},
|
|
256
|
+
webfetch: "deny",
|
|
257
|
+
websearch: "deny",
|
|
258
|
+
} as any,
|
|
259
|
+
}
|
|
260
|
+
|
|
238
261
|
// Block websearch for the primary agent globally.
|
|
239
262
|
// permission.ask hook is not triggered by OpenCode (no R.trigger call in binary).
|
|
240
263
|
// tool.execute.before throw is swallowed (trigger().catch(()=>{})).
|
|
@@ -313,6 +336,14 @@ const server: Plugin = (async (pluginCtx) => {
|
|
|
313
336
|
} as any)
|
|
314
337
|
return
|
|
315
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
|
+
}
|
|
316
347
|
if (sub === "edit") {
|
|
317
348
|
if (param) {
|
|
318
349
|
await send("`/revela edit` no longer accepts a target. It opens the only HTML deck in `decks/`.")
|
|
@@ -321,6 +352,14 @@ const server: Plugin = (async (pluginCtx) => {
|
|
|
321
352
|
await handleEdit({ client, sessionID, workspaceRoot }, send)
|
|
322
353
|
throw new Error("__REVELA_EDIT_HANDLED__")
|
|
323
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
|
+
}
|
|
324
363
|
if (sub === "designs" && !param) {
|
|
325
364
|
await handleDesignsList(send)
|
|
326
365
|
throw new Error("__REVELA_DESIGNS_LIST_HANDLED__")
|
|
@@ -419,6 +458,8 @@ const server: Plugin = (async (pluginCtx) => {
|
|
|
419
458
|
"revela-media-save": mediaSaveTool,
|
|
420
459
|
"revela-research-images-list": researchImagesListTool,
|
|
421
460
|
"revela-research-save": researchSaveTool,
|
|
461
|
+
"revela-inspection-context": inspectionContextTool,
|
|
462
|
+
"revela-inspection-result": inspectionResultTool,
|
|
422
463
|
"revela-workspace-scan": workspaceScanTool,
|
|
423
464
|
"revela-extract-document-materials": extractDocumentMaterialsTool,
|
|
424
465
|
"revela-qa": qaTool,
|
|
@@ -481,7 +522,7 @@ const server: Plugin = (async (pluginCtx) => {
|
|
|
481
522
|
|
|
482
523
|
// ── Inject three-layer prompt when enabled ─────────────────────────────
|
|
483
524
|
// Skip injection for:
|
|
484
|
-
// 1.
|
|
525
|
+
// 1. Revela subagents (they have focused prompts)
|
|
485
526
|
// 2. OpenCode internal agents (title, summary, compaction)
|
|
486
527
|
"experimental.chat.system.transform": async (input, output) => {
|
|
487
528
|
if (!ctx.enabled) return
|
|
@@ -498,6 +539,10 @@ const server: Plugin = (async (pluginCtx) => {
|
|
|
498
539
|
}
|
|
499
540
|
ctx.isResearchAgent = false
|
|
500
541
|
|
|
542
|
+
// Skip revela-narrative-reviewer subagent — it is read-only critique,
|
|
543
|
+
// not a deck-writing agent and not a research agent.
|
|
544
|
+
if (systemText.includes(NARRATIVE_REVIEWER_SIGNATURE)) return
|
|
545
|
+
|
|
501
546
|
// Skip OpenCode internal system agents (title generator, summary, compaction)
|
|
502
547
|
if (INTERNAL_AGENT_SIGNATURES.some((sig) => systemText.includes(sig))) return
|
|
503
548
|
|
package/skill/SKILL.md
CHANGED
|
@@ -83,6 +83,7 @@ Create or update the active deck in `DECKS.json` through `revela-decks` actions
|
|
|
83
83
|
`upsertDeck` and `upsertSlides`. Keep the deck spec current as work progresses:
|
|
84
84
|
- `goal` — purpose and decision/context
|
|
85
85
|
- `audience`, `language`, `outputPath`, and `theme`
|
|
86
|
+
- `narrativeBrief` — for substantial decision decks, the 0.9 compiler brief: audience belief before/after, decisionOrAction, narrativeArc, keyClaims, objections, and risks
|
|
86
87
|
- `requiredInputs` — checklist state for prewrite readiness
|
|
87
88
|
- `researchPlan` — axes, status, and findings files
|
|
88
89
|
- `slides` — confirmed per-slide title, purpose, layout, components, content, evidence, visuals, and status
|
|
@@ -200,6 +201,26 @@ state updates. Do not write temporary hypotheses, unsupported conclusions,
|
|
|
200
201
|
secrets, or inferred user preferences. User and workflow preferences require
|
|
201
202
|
explicit user intent to remember.
|
|
202
203
|
|
|
204
|
+
#### Narrative Review via `revela-narrative-reviewer`
|
|
205
|
+
|
|
206
|
+
`revela-narrative-reviewer` is a read-only OpenCode subagent, **not a tool**.
|
|
207
|
+
Launch it through the Task tool with `subagent_type: "revela-narrative-reviewer"`
|
|
208
|
+
when a substantial decision deck needs independent rubric-based critique of the
|
|
209
|
+
Narrative Compiler brief and slide-plan alignment.
|
|
210
|
+
|
|
211
|
+
Use it after the narrative brief and slide specs are recorded in `DECKS.json`,
|
|
212
|
+
and before treating narrative quality as reviewed. The primary agent should not
|
|
213
|
+
self-certify semantic narrative quality. `revela-decks review` remains the
|
|
214
|
+
authoritative write-readiness gate; reviewer findings are advisory notes only.
|
|
215
|
+
The reviewer uses stable finding IDs such as `NB-001`, `KC-001`, `ASK-001`, and
|
|
216
|
+
`EV-001`. If the fixed rubric passes, it should return `Findings: none` rather
|
|
217
|
+
than inventing optional improvements.
|
|
218
|
+
|
|
219
|
+
The reviewer may read `DECKS.json`, slide specs, evidence refs, and existing
|
|
220
|
+
`researches/{workspace-key}/*.md` files referenced by the deck. It must not write
|
|
221
|
+
state, call `upsertDeck`, call `upsertSlides`, call `revela-decks review`, use
|
|
222
|
+
websearch/webfetch, or generate/edit HTML.
|
|
223
|
+
|
|
203
224
|
#### AI Knowledge and User Questions
|
|
204
225
|
|
|
205
226
|
Use AI knowledge only to fill remaining gaps around verified sources. Mark it
|
|
@@ -213,6 +234,8 @@ already checked and what specific missing information is needed.
|
|
|
213
234
|
|
|
214
235
|
- **NEVER** use `websearch` directly from the primary agent; delegate web research to `revela-research` subagents
|
|
215
236
|
- **NEVER** call `revela-research` as a tool; use Task with `subagent_type: "revela-research"`
|
|
237
|
+
- **NEVER** call `revela-narrative-reviewer` as a tool; use Task with `subagent_type: "revela-narrative-reviewer"`
|
|
238
|
+
- **NEVER** present `revela-narrative-reviewer` findings as authoritative `revela-decks review` blockers or readiness issues
|
|
216
239
|
- **NEVER** collapse distinct research axes into one broad agent brief when parallel focused briefs would be clearer
|
|
217
240
|
- **ALWAYS** use `revela-decks` action `read` before deciding what research is needed
|
|
218
241
|
- **ALWAYS** read each `researches/{workspace-key}/{axis}.md` after agents complete
|
|
@@ -238,12 +261,17 @@ A 6-slide deck might be: Cover → Background → Content × 3 → Closing.
|
|
|
238
261
|
An 8-slide deck might be: Cover → TOC → Background → Content × 3 → Summary → Closing.
|
|
239
262
|
Never skip Cover, Background, or Closing regardless of deck length.
|
|
240
263
|
|
|
241
|
-
**Every `<section class="slide">` must include
|
|
242
|
-
`slide-qa="true"` for content-heavy layouts
|
|
243
|
-
QA column of the active design). Set
|
|
244
|
-
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"`.
|
|
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.
|
|
245
273
|
|
|
246
|
-
Example: `<section class="slide" slide-qa="true" data-index="
|
|
274
|
+
Example: `<section class="slide" slide-qa="true" data-slide-index="1">`
|
|
247
275
|
|
|
248
276
|
The export QA path treats this as deck metadata. It is consumed when PDF/PPTX
|
|
249
277
|
export runs preflight checks.
|
|
@@ -287,8 +315,17 @@ core rules and the visual design below.
|
|
|
287
315
|
|
|
288
316
|
### Phase 4 — Presentation Plan
|
|
289
317
|
|
|
290
|
-
After all research is complete and findings have been read, present a
|
|
291
|
-
slide plan to the user **before writing any HTML**.
|
|
318
|
+
After all research is complete and findings have been read, present a compact narrative brief
|
|
319
|
+
and a detailed slide plan to the user **before writing any HTML**.
|
|
320
|
+
|
|
321
|
+
For substantial decision decks, first summarize the Narrative Compiler brief:
|
|
322
|
+
- Audience belief before: what the audience currently believes, assumes, or does not yet understand
|
|
323
|
+
- Audience belief after: what the audience should believe or understand after the deck
|
|
324
|
+
- Decision/action: the approval, decision, behavior, or next step the deck should drive
|
|
325
|
+
- Narrative arc: the intended story path, such as context -> tension -> evidence -> recommendation -> risk -> ask
|
|
326
|
+
- Key claims: the main claims the deck must prove
|
|
327
|
+
- Likely objections: stakeholder resistance or questions the story should handle
|
|
328
|
+
- Risks/assumptions: caveats, tradeoffs, or uncertainty that should travel with the recommendation
|
|
292
329
|
|
|
293
330
|
Format the plan as a markdown table:
|
|
294
331
|
|
|
@@ -320,8 +357,9 @@ Then ask:
|
|
|
320
357
|
- On change request → update the table and ask again
|
|
321
358
|
|
|
322
359
|
After the user confirms the slide plan, update `DECKS.json` through `revela-decks`:
|
|
323
|
-
- Call `upsertDeck` to mark completed `requiredInputs` only when explicitly satisfied.
|
|
360
|
+
- Call `upsertDeck` to preserve `narrativeBrief` when available and mark completed `requiredInputs` only when explicitly satisfied.
|
|
324
361
|
- Call `upsertSlides` with the confirmed per-slide content, narrativeRole, layout, components, and evidence.
|
|
362
|
+
- For substantial decision decks, use Task with `subagent_type: "revela-narrative-reviewer"` for read-only rubric-based critique of narrativeBrief and slide-plan alignment. Ask for stable finding IDs and `Findings: none` when the rubric passes; do not ask the reviewer to write state, determine readiness, or brainstorm optional improvements.
|
|
325
363
|
- Keep write readiness blocked until Phase 5 calls `revela-decks review` and the tool returns ready.
|
|
326
364
|
|
|
327
365
|
---
|
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,
|
|
@@ -10,6 +11,7 @@ import {
|
|
|
10
11
|
writeDecksState,
|
|
11
12
|
workspaceDeckSlug,
|
|
12
13
|
type DeckSpec,
|
|
14
|
+
type NarrativeBrief,
|
|
13
15
|
type RequiredInputs,
|
|
14
16
|
type ResearchAxis,
|
|
15
17
|
type SourceMaterial,
|
|
@@ -24,13 +26,22 @@ export default tool({
|
|
|
24
26
|
"It stores active deck specs, per-slide content/layout/components, and computes write readiness.",
|
|
25
27
|
args: {
|
|
26
28
|
action: tool.schema
|
|
27
|
-
.enum(["read", "init", "upsertDeck", "upsertSlides", "review", "remember"])
|
|
29
|
+
.enum(["read", "init", "upsertDeck", "upsertSlides", "review", "applyEvidenceCandidates", "remember"])
|
|
28
30
|
.describe("Action to perform on DECKS.json."),
|
|
29
31
|
summary: tool.schema.boolean().optional().describe("For read: return a compact summary instead of full state."),
|
|
30
32
|
goal: tool.schema.string().optional().describe("For upsertDeck: deck goal."),
|
|
31
33
|
audience: tool.schema.string().optional().describe("For upsertDeck: deck audience."),
|
|
32
34
|
language: tool.schema.string().optional().describe("For upsertDeck: deck language."),
|
|
33
35
|
outputPath: tool.schema.string().optional().describe("For upsertDeck: target output path, normally decks/{workspace-name}.html."),
|
|
36
|
+
narrativeBrief: tool.schema.object({
|
|
37
|
+
audienceBeliefBefore: tool.schema.string().optional().describe("What the audience currently believes, assumes, or does not yet understand."),
|
|
38
|
+
audienceBeliefAfter: tool.schema.string().optional().describe("What the audience should believe or understand after the deck."),
|
|
39
|
+
decisionOrAction: tool.schema.string().optional().describe("The decision, approval, action, or behavioral change the deck is meant to drive."),
|
|
40
|
+
narrativeArc: tool.schema.string().optional().describe("Compact story arc, such as context -> tension -> evidence -> recommendation -> ask."),
|
|
41
|
+
keyClaims: tool.schema.array(tool.schema.string()).optional().describe("Main claims the deck must prove or communicate."),
|
|
42
|
+
objections: tool.schema.array(tool.schema.string()).optional().describe("Likely stakeholder objections or questions the narrative should handle."),
|
|
43
|
+
risks: tool.schema.array(tool.schema.string()).optional().describe("Risks, assumptions, caveats, or tradeoffs that should travel with the narrative."),
|
|
44
|
+
}).optional().describe("For upsertDeck: 0.9 Narrative Compiler brief used to review story intent before writing."),
|
|
34
45
|
design: tool.schema.string().optional().describe("For upsertDeck: active design name."),
|
|
35
46
|
domain: tool.schema.string().optional().describe("For upsertDeck: active domain name."),
|
|
36
47
|
memory: tool.schema.string().optional().describe("For remember: explicit user or workflow preference to store."),
|
|
@@ -106,6 +117,7 @@ export default tool({
|
|
|
106
117
|
status: tool.schema.enum(["planned", "ready", "written", "qa_passed", "qa_failed"]).optional().describe("Slide production status."),
|
|
107
118
|
notes: tool.schema.string().optional().describe("Implementation notes for this slide."),
|
|
108
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."),
|
|
109
121
|
},
|
|
110
122
|
async execute(args, context) {
|
|
111
123
|
try {
|
|
@@ -140,6 +152,7 @@ export default tool({
|
|
|
140
152
|
audience: args.audience ?? existing?.audience,
|
|
141
153
|
language: args.language ?? existing?.language,
|
|
142
154
|
outputPath: args.outputPath ?? existing?.outputPath,
|
|
155
|
+
narrativeBrief: (args.narrativeBrief as NarrativeBrief | undefined) ?? existing?.narrativeBrief,
|
|
143
156
|
theme: {
|
|
144
157
|
design: args.design ?? existing?.theme?.design,
|
|
145
158
|
domain: args.domain ?? existing?.theme?.domain,
|
|
@@ -164,11 +177,19 @@ export default tool({
|
|
|
164
177
|
}
|
|
165
178
|
|
|
166
179
|
if (args.action === "review") {
|
|
167
|
-
const reviewed = reviewDeckState(state)
|
|
180
|
+
const reviewed = reviewDeckState(state, undefined, { workspaceRoot })
|
|
168
181
|
writeDecksState(workspaceRoot, reviewed.state)
|
|
169
182
|
return JSON.stringify({ ok: true, path: DECKS_STATE_FILE, result: reviewed.result }, null, 2)
|
|
170
183
|
}
|
|
171
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
|
+
|
|
172
193
|
if (args.action === "remember") {
|
|
173
194
|
const memory = args.memory?.trim()
|
|
174
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
|
+
})
|