@cyber-dash-tech/revela 0.18.3 → 0.18.4

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 CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  **English** | [中文](README.zh-CN.md)
4
4
 
5
- [![npm version](https://img.shields.io/npm/v/@cyber-dash-tech/revela)](https://www.npmjs.com/package/@cyber-dash-tech/revela) [![license](https://img.shields.io/npm/l/@cyber-dash-tech/revela)](LICENSE) [![tests](https://img.shields.io/badge/tests-688%20passing-brightgreen)](tests/) [![OpenCode plugin](https://img.shields.io/badge/OpenCode-plugin-blue)](https://opencode.ai) [![Bun](https://img.shields.io/badge/Bun-%E2%89%A51.0-orange)](https://bun.sh)
5
+ [![npm version](https://img.shields.io/npm/v/@cyber-dash-tech/revela)](https://www.npmjs.com/package/@cyber-dash-tech/revela) [![license](https://img.shields.io/npm/l/@cyber-dash-tech/revela)](LICENSE) [![tests](https://img.shields.io/badge/tests-691%20passing-brightgreen)](tests/) [![OpenCode plugin](https://img.shields.io/badge/OpenCode-plugin-blue)](https://opencode.ai) [![Bun](https://img.shields.io/badge/Bun-%E2%89%A51.0-orange)](https://bun.sh)
6
6
 
7
7
  <p align="center">
8
8
  <img src="assets/img/logo.png" alt="Revela" width="560" />
@@ -34,7 +34,7 @@ To install globally, add the same entry to `~/.config/opencode/opencode.json`.
34
34
  Requirements:
35
35
 
36
36
  - The Codex CLI must be installed and the `codex` command must be available in your shell.
37
- - Your environment must be able to run `npx`; Revela uses `npx -y @cyber-dash-tech/revela@0.18.3 mcp` to start the MCP server.
37
+ - Your environment must be able to run `npx`; Revela uses `npx -y @cyber-dash-tech/revela@0.18.4 mcp` to start the MCP server.
38
38
  - For interactive Review actions, `codex exec` must also work because the Review UI uses it for Comment/Apply Fix requests.
39
39
 
40
40
  Optional preflight:
@@ -55,11 +55,11 @@ npm_config_cache=/tmp/revela-npm-cache bun run smoke:mcp-pack
55
55
  Install Revela through the Codex Git marketplace:
56
56
 
57
57
  ```bash
58
- codex plugin marketplace add https://github.com/cyber-dash-tech/revela --ref v0.18.3
58
+ codex plugin marketplace add https://github.com/cyber-dash-tech/revela --ref v0.18.4
59
59
  codex plugin add revela@revela
60
60
  ```
61
61
 
62
- The Git marketplace install provides the Codex plugin shell, skills, hooks, and MCP configuration. When Codex starts the Revela MCP server for the first time, it runs `npx -y @cyber-dash-tech/revela@0.18.3 mcp` so npm can fetch the published package and its dependencies.
62
+ The Git marketplace install provides the Codex plugin shell, skills, hooks, and MCP configuration. When Codex starts the Revela MCP server for the first time, it runs `npx -y @cyber-dash-tech/revela@0.18.4 mcp` so npm can fetch the published package and its dependencies.
63
63
 
64
64
  You do not need to run `bun install` inside the Codex marketplace clone.
65
65
 
package/README.zh-CN.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  [English](README.md) | **中文**
4
4
 
5
- [![npm version](https://img.shields.io/npm/v/@cyber-dash-tech/revela)](https://www.npmjs.com/package/@cyber-dash-tech/revela) [![license](https://img.shields.io/npm/l/@cyber-dash-tech/revela)](LICENSE) [![tests](https://img.shields.io/badge/tests-688%20passing-brightgreen)](tests/) [![OpenCode plugin](https://img.shields.io/badge/OpenCode-plugin-blue)](https://opencode.ai) [![Bun](https://img.shields.io/badge/Bun-%E2%89%A51.0-orange)](https://bun.sh)
5
+ [![npm version](https://img.shields.io/npm/v/@cyber-dash-tech/revela)](https://www.npmjs.com/package/@cyber-dash-tech/revela) [![license](https://img.shields.io/npm/l/@cyber-dash-tech/revela)](LICENSE) [![tests](https://img.shields.io/badge/tests-691%20passing-brightgreen)](tests/) [![OpenCode plugin](https://img.shields.io/badge/OpenCode-plugin-blue)](https://opencode.ai) [![Bun](https://img.shields.io/badge/Bun-%E2%89%A51.0-orange)](https://bun.sh)
6
6
 
7
7
  <p align="center">
8
8
  <img src="assets/img/logo.png" alt="Revela" width="560" />
@@ -34,7 +34,7 @@ Revela 可在 [OpenCode](https://opencode.ai) 和 Codex 中使用,把来源材
34
34
  环境要求:
35
35
 
36
36
  - 需要已安装 Codex CLI,并且 shell 中可以执行 `codex`。
37
- - 环境中需要可以执行 `npx`;Revela 会用 `npx -y @cyber-dash-tech/revela@0.18.3 mcp` 启动 MCP server。
37
+ - 环境中需要可以执行 `npx`;Revela 会用 `npx -y @cyber-dash-tech/revela@0.18.4 mcp` 启动 MCP server。
38
38
  - 如果使用 Review UI 的 Comment 或 Apply Fix,需要 `codex exec` 可用。
39
39
 
40
40
  可选的安装前检查:
@@ -55,11 +55,11 @@ npm_config_cache=/tmp/revela-npm-cache bun run smoke:mcp-pack
55
55
  通过 Codex Git marketplace 安装 Revela:
56
56
 
57
57
  ```bash
58
- codex plugin marketplace add https://github.com/cyber-dash-tech/revela --ref v0.18.3
58
+ codex plugin marketplace add https://github.com/cyber-dash-tech/revela --ref v0.18.4
59
59
  codex plugin add revela@revela
60
60
  ```
61
61
 
62
- Git marketplace 安装的是 Codex plugin 壳、skills、hooks 和 MCP 配置。Codex 第一次启动 Revela MCP server 时,会运行 `npx -y @cyber-dash-tech/revela@0.18.3 mcp`,由 npm 获取已发布 package 及其 dependencies。
62
+ Git marketplace 安装的是 Codex plugin 壳、skills、hooks 和 MCP 配置。Codex 第一次启动 Revela MCP server 时,会运行 `npx -y @cyber-dash-tech/revela@0.18.4 mcp`,由 npm 获取已发布 package 及其 dependencies。
63
63
 
64
64
  不需要在 Codex marketplace clone 里运行 `bun install`。
65
65
 
@@ -1651,6 +1651,7 @@ function isIgnorableSourceMaterial(path: string): boolean {
1651
1651
  normalized.startsWith("decks/") ||
1652
1652
  normalized.startsWith("researches/") ||
1653
1653
  normalized.startsWith("assets/") ||
1654
+ normalized.startsWith(".revela/") ||
1654
1655
  normalized.startsWith(".opencode/"),
1655
1656
  )
1656
1657
  }
@@ -11,6 +11,7 @@ import { extractXlsx } from "../read-hooks/extractors/xlsx"
11
11
  import { hasDecksState, readDecksState, writeDecksState } from "../decks-state"
12
12
  import { computeSourceFingerprint, sourceMaterialMetadata, upsertSourceMaterial } from "../source-materials"
13
13
  import { recordWorkspaceAction } from "../workspace-state/actions"
14
+ import { existingWorkspaceMetaPath, workspaceMetaPath } from "../workspace-meta"
14
15
 
15
16
  export type DocumentMaterial = {
16
17
  path: string
@@ -852,7 +853,7 @@ async function extractPdfImages(buf: Buffer, cacheDir: string, workspaceDir: str
852
853
  async function processPdfFile(filePath: string, workspaceDir: string): Promise<DocumentMaterialsResult> {
853
854
  const relativeSource = workspaceRelative(filePath, workspaceDir)
854
855
  const fingerprint = buildFingerprint(filePath)
855
- const cacheDir = join(workspaceDir, ".opencode", "revela", "doc-materials", fingerprint)
856
+ const cacheDir = existingWorkspaceMetaPath(workspaceDir, "doc-materials", fingerprint)
856
857
  const manifestPath = join(cacheDir, "manifest.json")
857
858
 
858
859
  if (existsSync(manifestPath)) {
@@ -874,19 +875,21 @@ async function processPdfFile(filePath: string, workspaceDir: string): Promise<D
874
875
  }
875
876
  }
876
877
 
877
- mkdirSync(join(cacheDir, "images"), { recursive: true })
878
- mkdirSync(join(cacheDir, "tables"), { recursive: true })
878
+ const writeCacheDir = workspaceMetaPath(workspaceDir, "doc-materials", fingerprint)
879
+ const writeManifestPath = join(writeCacheDir, "manifest.json")
880
+ mkdirSync(join(writeCacheDir, "images"), { recursive: true })
881
+ mkdirSync(join(writeCacheDir, "tables"), { recursive: true })
879
882
 
880
883
  const buf = readFileSync(filePath)
881
884
  const text = await extractPdfText(buf)
882
- const textPath = join(cacheDir, "text.txt")
885
+ const textPath = join(writeCacheDir, "text.txt")
883
886
  writeFileSync(textPath, `[Extracted from: ${basename(filePath)}]\n\n${text}`, "utf-8")
884
887
 
885
- const images = await extractPdfImages(buf, cacheDir, workspaceDir)
886
- const relativeManifestPath = workspaceRelative(manifestPath, workspaceDir)
888
+ const images = await extractPdfImages(buf, writeCacheDir, workspaceDir)
889
+ const relativeManifestPath = workspaceRelative(writeManifestPath, workspaceDir)
887
890
  const relativeTextPath = workspaceRelative(textPath, workspaceDir)
888
891
  const readViewPath = writeReadView({
889
- cacheDir,
892
+ cacheDir: writeCacheDir,
890
893
  workspaceDir,
891
894
  source: relativeSource,
892
895
  type: "pdf",
@@ -905,7 +908,7 @@ async function processPdfFile(filePath: string, workspaceDir: string): Promise<D
905
908
  cache_status: "miss",
906
909
  source: relativeSource,
907
910
  type: "pdf",
908
- cache_dir: workspaceRelative(cacheDir, workspaceDir),
911
+ cache_dir: workspaceRelative(writeCacheDir, workspaceDir),
909
912
  manifest_path: relativeManifestPath,
910
913
  text_path: relativeTextPath,
911
914
  read_view_path: readViewPath,
@@ -929,14 +932,14 @@ async function processPdfFile(filePath: string, workspaceDir: string): Promise<D
929
932
  tables: [],
930
933
  }
931
934
 
932
- writeFileSync(manifestPath, JSON.stringify(manifest, null, 2), "utf-8")
935
+ writeFileSync(writeManifestPath, JSON.stringify(manifest, null, 2), "utf-8")
933
936
  return result
934
937
  }
935
938
 
936
939
  async function processOfficeFile(filePath: string, workspaceDir: string, type: SupportedType): Promise<DocumentMaterialsResult> {
937
940
  const relativeSource = workspaceRelative(filePath, workspaceDir)
938
941
  const fingerprint = buildFingerprint(filePath)
939
- const cacheDir = join(workspaceDir, ".opencode", "revela", "doc-materials", fingerprint)
942
+ const cacheDir = existingWorkspaceMetaPath(workspaceDir, "doc-materials", fingerprint)
940
943
  const manifestPath = join(cacheDir, "manifest.json")
941
944
 
942
945
  if (existsSync(manifestPath)) {
@@ -958,8 +961,10 @@ async function processOfficeFile(filePath: string, workspaceDir: string, type: S
958
961
  }
959
962
  }
960
963
 
961
- mkdirSync(join(cacheDir, "images"), { recursive: true })
962
- mkdirSync(join(cacheDir, "tables"), { recursive: true })
964
+ const writeCacheDir = workspaceMetaPath(workspaceDir, "doc-materials", fingerprint)
965
+ const writeManifestPath = join(writeCacheDir, "manifest.json")
966
+ mkdirSync(join(writeCacheDir, "images"), { recursive: true })
967
+ mkdirSync(join(writeCacheDir, "tables"), { recursive: true })
963
968
 
964
969
  const buf = readFileSync(filePath)
965
970
  const files = unzipSync(new Uint8Array(buf))
@@ -970,26 +975,26 @@ async function processOfficeFile(filePath: string, workspaceDir: string, type: S
970
975
  ? await extractDocx(buf)
971
976
  : await extractXlsx(buf)
972
977
 
973
- const textPath = join(cacheDir, "text.txt")
978
+ const textPath = join(writeCacheDir, "text.txt")
974
979
  writeFileSync(textPath, `[Extracted from: ${basename(filePath)}]\n\n${text}`, "utf-8")
975
980
 
976
981
  const pptxAssets = type === "pptx"
977
- ? extractPptxImages(files, cacheDir, workspaceDir)
982
+ ? extractPptxImages(files, writeCacheDir, workspaceDir)
978
983
  : null
979
984
  const images = type === "pptx"
980
985
  ? pptxAssets!.images
981
986
  : type === "docx"
982
- ? extractDocxImages(files, cacheDir, workspaceDir)
983
- : extractXlsxImages(files, cacheDir, workspaceDir)
987
+ ? extractDocxImages(files, writeCacheDir, workspaceDir)
988
+ : extractXlsxImages(files, writeCacheDir, workspaceDir)
984
989
  const slides = type === "pptx"
985
990
  ? extractPptxSlides(files, images, pptxAssets!.skipped_assets)
986
991
  : undefined
987
- const relativeManifestPath = workspaceRelative(manifestPath, workspaceDir)
992
+ const relativeManifestPath = workspaceRelative(writeManifestPath, workspaceDir)
988
993
  const relativeTextPath = workspaceRelative(textPath, workspaceDir)
989
994
  const tables = extractTables(type, relativeTextPath)
990
995
  const skippedAssets = pptxAssets?.skipped_assets ?? []
991
996
  const readViewPath = writeReadView({
992
- cacheDir,
997
+ cacheDir: writeCacheDir,
993
998
  workspaceDir,
994
999
  source: relativeSource,
995
1000
  type,
@@ -1008,7 +1013,7 @@ async function processOfficeFile(filePath: string, workspaceDir: string, type: S
1008
1013
  cache_status: "miss",
1009
1014
  source: relativeSource,
1010
1015
  type,
1011
- cache_dir: workspaceRelative(cacheDir, workspaceDir),
1016
+ cache_dir: workspaceRelative(writeCacheDir, workspaceDir),
1012
1017
  manifest_path: relativeManifestPath,
1013
1018
  text_path: relativeTextPath,
1014
1019
  read_view_path: readViewPath,
@@ -1032,7 +1037,7 @@ async function processOfficeFile(filePath: string, workspaceDir: string, type: S
1032
1037
  tables: result.tables ?? [],
1033
1038
  }
1034
1039
 
1035
- writeFileSync(manifestPath, JSON.stringify(manifest, null, 2), "utf-8")
1040
+ writeFileSync(writeManifestPath, JSON.stringify(manifest, null, 2), "utf-8")
1036
1041
  return result
1037
1042
  }
1038
1043
 
@@ -3,6 +3,7 @@ import { basename, extname, isAbsolute, join, relative, resolve, sep } from "pat
3
3
  import { extractDocumentMaterials, type DocumentMaterialsResult } from "./document-materials/extract"
4
4
  import { sourceMaterialMetadata, sourceMaterialType } from "./source-materials"
5
5
  import type { SourceMaterial } from "./decks-state"
6
+ import { existingWorkspaceMetaPath, workspaceMetaPath } from "./workspace-meta"
6
7
 
7
8
  export type MaterialIntakeStatus =
8
9
  | "scanned"
@@ -107,24 +108,28 @@ export interface CheckMaterialIntakeResult {
107
108
  }
108
109
 
109
110
  const DOC_EXTENSIONS = new Set([".pdf", ".docx", ".doc", ".xlsx", ".xls", ".pptx", ".ppt", ".csv", ".md", ".txt"])
110
- const EXCLUDE_DIRS = new Set(["node_modules", ".git", "dist", ".opencode", "researches", "revela-narrative", "designs", "domains"])
111
+ const EXCLUDE_DIRS = new Set(["node_modules", ".git", "dist", ".opencode", ".revela", "researches", "revela-narrative", "designs", "domains"])
111
112
  const EXCLUDE_FILENAMES = new Set(["AGENTS.md", "DECKS.md", "README.md", "README.zh-CN.md"])
112
113
  const EXTRACTION_EXTENSIONS = new Set(["pdf", "ppt", "pptx", "doc", "docx", "xls", "xlsx"])
113
114
  const SUPPORTED_EXTRACTION_EXTENSIONS = new Set(["pdf", "pptx", "docx", "xlsx"])
114
115
 
115
116
  export function materialRegistryPath(workspaceRoot: string): string {
116
- return join(workspaceRoot, ".opencode", "revela", "material-intake", "registry.json")
117
+ return workspaceMetaPath(workspaceRoot, "material-intake", "registry.json")
118
+ }
119
+
120
+ function existingMaterialRegistryPath(workspaceRoot: string): string {
121
+ return existingWorkspaceMetaPath(workspaceRoot, "material-intake", "registry.json")
117
122
  }
118
123
 
119
124
  export function readMaterialRegistry(workspaceRoot: string): MaterialRegistry {
120
- const path = materialRegistryPath(workspaceRoot)
125
+ const path = existingMaterialRegistryPath(workspaceRoot)
121
126
  if (!existsSync(path)) return { version: 1, updatedAt: new Date(0).toISOString(), sources: [] }
122
127
  return JSON.parse(readFileSync(path, "utf-8")) as MaterialRegistry
123
128
  }
124
129
 
125
130
  export function writeMaterialRegistry(workspaceRoot: string, registry: MaterialRegistry): string {
126
131
  const path = materialRegistryPath(workspaceRoot)
127
- mkdirSync(join(workspaceRoot, ".opencode", "revela", "material-intake"), { recursive: true })
132
+ mkdirSync(join(workspaceRoot, ".revela", "material-intake"), { recursive: true })
128
133
  writeFileSync(path, JSON.stringify({ ...registry, updatedAt: new Date().toISOString() }, null, 2), "utf-8")
129
134
  return workspaceRelative(path, workspaceRoot)
130
135
  }
@@ -1,5 +1,5 @@
1
1
  export const NARRATIVE_VAULT_DIR = "revela-narrative"
2
- export const NARRATIVE_VAULT_CACHE_DIR = ".opencode/revela/narrative-cache"
2
+ export const NARRATIVE_VAULT_CACHE_DIR = ".revela/narrative-cache"
3
3
 
4
4
  export const NARRATIVE_VAULT_NODE_DIRS = ["claims", "evidence", "objections", "risks", "research-gaps"] as const
5
5
 
@@ -1,13 +1,18 @@
1
1
  import { existsSync } from "fs"
2
2
  import { join } from "path"
3
- import { NARRATIVE_VAULT_CACHE_DIR, NARRATIVE_VAULT_DIR } from "./constants"
3
+ import { existingWorkspaceMetaPath, workspaceMetaPath } from "../workspace-meta"
4
+ import { NARRATIVE_VAULT_DIR } from "./constants"
4
5
 
5
6
  export function narrativeVaultPath(workspaceRoot: string): string {
6
7
  return join(workspaceRoot, NARRATIVE_VAULT_DIR)
7
8
  }
8
9
 
9
10
  export function narrativeVaultCachePath(workspaceRoot: string): string {
10
- return join(workspaceRoot, NARRATIVE_VAULT_CACHE_DIR)
11
+ return workspaceMetaPath(workspaceRoot, "narrative-cache")
12
+ }
13
+
14
+ export function existingNarrativeVaultCachePath(workspaceRoot: string): string {
15
+ return existingWorkspaceMetaPath(workspaceRoot, "narrative-cache")
11
16
  }
12
17
 
13
18
  export function hasNarrativeVault(workspaceRoot: string): boolean {
@@ -27,6 +27,7 @@ import { formatArtifactQaUserNotice, formatMarkdownQaUserNotice } from "../hook-
27
27
  import { deckPlanDesignDiagnostics, readDeckPlanArtifact, upsertDeckPlanSlideArtifact, type DeckPlanSlideUpsertInput } from "../narrative-state/deck-plan-artifact"
28
28
  import { extractDesignClasses } from "../design/designs"
29
29
  import { recordRenderedArtifact, workspaceRelative } from "../workspace-state/rendered-artifacts"
30
+ import { existingWorkspaceMetaPath, workspaceMetaPath } from "../workspace-meta"
30
31
  import { checkMaterialIntake, extractMaterial, materialIntakeNoticeForCommand, prepareLocalMaterials, recordMaterialReview } from "../material-intake"
31
32
  import type { ReviewDeckOpenInput, ReviewDeckReadInput } from "./review"
32
33
  import pkg from "../../package.json"
@@ -414,7 +415,7 @@ export function checkDesignRulesReadiness(input: RuntimeWorkspaceInput = {}): De
414
415
  }
415
416
 
416
417
  function recordDesignRulesRead(workspaceRoot: string, designName: string, rules: string): void {
417
- const markerPath = designRulesMarkerPath(workspaceRoot)
418
+ const markerPath = workspaceMetaPath(workspaceRoot, "codex-hooks", "design-rules-read.json")
418
419
  mkdirSync(dirname(markerPath), { recursive: true })
419
420
  writeFileSync(markerPath, JSON.stringify({
420
421
  designName,
@@ -424,7 +425,7 @@ function recordDesignRulesRead(workspaceRoot: string, designName: string, rules:
424
425
  }
425
426
 
426
427
  function designRulesMarkerPath(workspaceRoot: string): string {
427
- return resolve(workspaceRoot, ".opencode", "revela", "codex-hooks", "design-rules-read.json")
428
+ return existingWorkspaceMetaPath(workspaceRoot, "codex-hooks", "design-rules-read.json")
428
429
  }
429
430
 
430
431
  function hashDesignRules(rules: string): string {
@@ -0,0 +1,32 @@
1
+ import { existsSync } from "fs"
2
+ import { join } from "path"
3
+
4
+ export const WORKSPACE_META_DIR = ".revela"
5
+ export const LEGACY_WORKSPACE_META_DIR = ".opencode/revela"
6
+
7
+ export function workspaceMetaPath(workspaceRoot: string, ...segments: string[]): string {
8
+ return join(workspaceRoot, WORKSPACE_META_DIR, ...segments)
9
+ }
10
+
11
+ export function legacyWorkspaceMetaPath(workspaceRoot: string, ...segments: string[]): string {
12
+ return join(workspaceRoot, LEGACY_WORKSPACE_META_DIR, ...segments)
13
+ }
14
+
15
+ export function existingWorkspaceMetaPath(workspaceRoot: string, ...segments: string[]): string {
16
+ const current = workspaceMetaPath(workspaceRoot, ...segments)
17
+ if (existsSync(current)) return current
18
+ const legacy = legacyWorkspaceMetaPath(workspaceRoot, ...segments)
19
+ return existsSync(legacy) ? legacy : current
20
+ }
21
+
22
+ export function workspaceMetaRelativePath(...segments: string[]): string {
23
+ return join(WORKSPACE_META_DIR, ...segments).replace(/\\/g, "/")
24
+ }
25
+
26
+ export function isWorkspaceMetaRelativePath(path: string): boolean {
27
+ const normalized = path.replace(/\\/g, "/").replace(/^\.\//, "")
28
+ return normalized === WORKSPACE_META_DIR ||
29
+ normalized.startsWith(`${WORKSPACE_META_DIR}/`) ||
30
+ normalized === ".opencode" ||
31
+ normalized.startsWith(".opencode/")
32
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cyber-dash-tech/revela",
3
- "version": "0.18.3",
3
+ "version": "0.18.4",
4
4
  "description": "OpenCode plugin for trusted narrative artifacts from local sources, research, and evidence",
5
5
  "type": "module",
6
6
  "main": "./index.ts",
package/plugin.ts CHANGED
@@ -98,6 +98,7 @@ import { extractDesignClasses } from "./lib/design/designs"
98
98
  import { log, childLog } from "./lib/log"
99
99
  import { appendToolResult } from "./lib/tool-result"
100
100
  import { formatArtifactQaUserNotice, formatMarkdownQaUserNotice, formatStateGateUserNotice } from "./lib/hook-notifications"
101
+ import { workspaceMetaPath, workspaceMetaRelativePath } from "./lib/workspace-meta"
101
102
 
102
103
  // OpenCode internal agent signatures — used to skip system prompt injection
103
104
  // for built-in system agents (title, summary, compaction).
@@ -712,7 +713,7 @@ const server: Plugin = (async (pluginCtx) => {
712
713
  if (input.tool === "write") {
713
714
  const filePath: string = (output.args as any)?.filePath ?? ""
714
715
  if (isDecksStatePath(filePath)) {
715
- const blockedDir = join(workspaceRoot, ".opencode", "revela", "blocked-writes")
716
+ const blockedDir = workspaceMetaPath(workspaceRoot, "blocked-writes")
716
717
  mkdirSync(blockedDir, { recursive: true })
717
718
  const blockedPath = join(blockedDir, "DECKS-json-direct-write.blocked.md")
718
719
  const blocker = `${DECKS_STATE_FILE} is a controlled Revela state file. Use the revela-decks tool instead of write/apply_patch.`
@@ -738,9 +739,9 @@ Next step: use \`revela-decks\` with action \`init\`, \`upsertDeck\`, \`upsertSl
738
739
 
739
740
  const stateTargets = extractDecksStateTargetsFromPatch(patchText)
740
741
  if (stateTargets.length > 0) {
741
- const blockedDir = join(workspaceRoot, ".opencode", "revela", "blocked-writes")
742
+ const blockedDir = workspaceMetaPath(workspaceRoot, "blocked-writes")
742
743
  mkdirSync(blockedDir, { recursive: true })
743
- const blockedRelativePath = `.opencode/revela/blocked-writes/DECKS-json-direct-patch-${Date.now()}.blocked.md`
744
+ const blockedRelativePath = workspaceMetaRelativePath("blocked-writes", `DECKS-json-direct-patch-${Date.now()}.blocked.md`)
744
745
  const blocker = `${DECKS_STATE_FILE} is a controlled Revela state file. Use the revela-decks tool instead of write/apply_patch.`
745
746
  const blockedPatch = `*** Begin Patch
746
747
  *** Add File: ${blockedRelativePath}
@@ -2,7 +2,7 @@
2
2
  "mcpServers": {
3
3
  "revela": {
4
4
  "command": "npx",
5
- "args": ["-y", "@cyber-dash-tech/revela@0.18.3", "mcp"]
5
+ "args": ["-y", "@cyber-dash-tech/revela@0.18.4", "mcp"]
6
6
  }
7
7
  }
8
8
  }
@@ -22,7 +22,7 @@ export async function runPreWriteChecks(input: string): Promise<HookResult> {
22
22
  messages.push([
23
23
  "Revela narrative cache patches are blocked.",
24
24
  `Controlled cache target(s): ${cacheTargets.map((target) => `\`${target}\``).join(", ")}`,
25
- "Edit `revela-narrative/**/*.md` instead; compile/cache files under `.opencode/revela/narrative-cache/` are regenerated.",
25
+ "Edit `revela-narrative/**/*.md` instead; compile/cache files under `.revela/narrative-cache/` are regenerated.",
26
26
  ].join("\n"))
27
27
  }
28
28
 
@@ -67,7 +67,7 @@ export function extractDeckHtmlPatchTargets(input: string): string[] {
67
67
  export function extractNarrativeCachePatchTargets(input: string): string[] {
68
68
  const targets = new Set<string>()
69
69
  for (const patch of patchPayloads(input)) {
70
- const pattern = /(?:^\*\*\* Update File: |^\*\*\* Add File: |^\*\*\* Delete File: |^\*\*\* Move to: )([^\r\n]*\.opencode\/revela\/narrative-cache\/[^\r\n]+)\s*$/gm
70
+ const pattern = /(?:^\*\*\* Update File: |^\*\*\* Add File: |^\*\*\* Delete File: |^\*\*\* Move to: )([^\r\n]*(?:\.revela|\.opencode\/revela)\/narrative-cache\/[^\r\n]+)\s*$/gm
71
71
  let match: RegExpExecArray | null
72
72
  while ((match = pattern.exec(patch))) targets.add(match[1].trim())
73
73
  }
@@ -13,7 +13,7 @@ const DOC_EXTENSIONS = new Set([
13
13
 
14
14
  // Directories to exclude from scanning
15
15
  const EXCLUDE_DIRS = new Set([
16
- "node_modules", ".git", "dist", ".opencode",
16
+ "node_modules", ".git", "dist", ".opencode", ".revela",
17
17
  "researches", // Exclude revela's own research output
18
18
  "revela-narrative", // Exclude canonical narrative vault source files
19
19
  "designs", "domains", // Exclude revela plugin assets