echoes-vault-opencode 1.0.32 → 1.0.33

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.
Files changed (2) hide show
  1. package/package.json +1 -1
  2. package/tui.tsx +130 -10
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "echoes-vault-opencode",
3
- "version": "1.0.32",
3
+ "version": "1.0.33",
4
4
  "description": "EchoesVault — persistent memory plugin for OpenCode. Obsidian-style knowledge base with daily logs, encyclopedia pages, and session resumption.",
5
5
  "type": "module",
6
6
  "main": "index.ts",
package/tui.tsx CHANGED
@@ -1,30 +1,150 @@
1
1
  /** @jsxImportSource @opentui/solid */
2
+ import { createSignal } from "solid-js"
2
3
  import type { TuiPlugin } from "@opencode-ai/plugin/tui"
3
4
 
5
+ type VaultStatus = "uninitialized" | "idle" | "working" | "saved"
6
+
7
+ const KV = "echoes_vault_state"
8
+
9
+ const STATUS_META: Record<VaultStatus, { label: string; description: string; colorKey: string }> = {
10
+ uninitialized: {
11
+ label: "Vault not initialized",
12
+ description: 'Run /echoes-init to create EchoesVault',
13
+ colorKey: "error",
14
+ },
15
+ idle: {
16
+ label: "Vault idle",
17
+ description: 'Run /echoes-start to restore context from vault',
18
+ colorKey: "warning",
19
+ },
20
+ working: {
21
+ label: "Vault active",
22
+ description: 'Run /echoes-end before closing to save session memory',
23
+ colorKey: "success",
24
+ },
25
+ saved: {
26
+ label: "Session saved",
27
+ description: 'Memory committed to EchoesVault',
28
+ colorKey: "accent",
29
+ },
30
+ }
31
+
32
+ function computeStatus(init: boolean, started: boolean, ended: boolean): VaultStatus {
33
+ if (!init) return "uninitialized"
34
+ if (ended) return "saved"
35
+ if (started) return "working"
36
+ return "idle"
37
+ }
38
+
4
39
  const tui: TuiPlugin = async (api) => {
5
40
  const theme = api.theme.current
6
41
 
42
+ const [getInit, setInit] = createSignal(false)
43
+ const [getStarted, setStarted] = createSignal(false)
44
+ const [getEnded, setEnded] = createSignal(false)
45
+
46
+ try {
47
+ const raw = api.kv.get<{ initialized: boolean }>(KV)
48
+ if (raw?.initialized) setInit(true)
49
+ } catch {}
50
+
51
+ function persist() {
52
+ try { api.kv.set(KV, { initialized: getInit() }) } catch {}
53
+ }
54
+
55
+ function handleCommand(cmd: "init" | "start" | "end") {
56
+ if (cmd === "init") {
57
+ setInit(true)
58
+ setStarted(false)
59
+ setEnded(false)
60
+ } else if (cmd === "start") {
61
+ setStarted(true)
62
+ setEnded(false)
63
+ } else if (cmd === "end") {
64
+ setEnded(true)
65
+ }
66
+ persist()
67
+ }
68
+
69
+ api.event.on("session.created", () => {
70
+ setStarted(false)
71
+ setEnded(false)
72
+ })
73
+
74
+ api.event.on("session.idle", () => {
75
+ if (getStarted() && !getEnded()) {
76
+ setStarted(false)
77
+ }
78
+ })
79
+
80
+ api.event.on("message.part.updated", (event: any) => {
81
+ try {
82
+ const part = event?.properties?.part
83
+ if (!part) return
84
+ const text: string = part.text ?? part.content ?? ""
85
+ if (typeof text !== "string") return
86
+
87
+ if (text.includes("/echoes-init")) handleCommand("init")
88
+ else if (text.includes("/echoes-start")) handleCommand("start")
89
+ else if (text.includes("/echoes-end")) handleCommand("end")
90
+ } catch {}
91
+ })
92
+
7
93
  api.slots.register({
8
94
  slots: {
9
95
  sidebar_content() {
96
+ const status = computeStatus(getInit(), getStarted(), getEnded())
97
+ const meta = STATUS_META[status]
98
+ const color = (theme as any)[meta.colorKey] ?? theme.text
99
+
10
100
  return (
11
- <box flexDirection="column">
101
+ <box flexDirection="column">
102
+ <box border="all" borderStyle="single" paddingX={1} paddingY={0}>
12
103
  <text fg={theme.text}>
13
- <b>EchoesVault Controls</b>
104
+ <b>EchoesVault</b>
105
+ </text>
106
+ </box>
107
+
108
+ <box paddingX={1} paddingY={0} marginTop={1}>
109
+ <text fg={color}>
110
+ <b>{meta.label}</b>
111
+ </text>
112
+ </box>
113
+
114
+ <box paddingX={1} paddingY={0}>
115
+ <text fg={theme.textMuted}>{meta.description}</text>
116
+ </box>
117
+
118
+ <box paddingX={1} paddingY={0} marginTop={1}>
119
+ <text fg={theme.textMuted}>
120
+ <b>Commands</b>
14
121
  </text>
122
+ </box>
123
+
124
+ <box paddingX={1} paddingY={0}>
125
+ <text fg={theme.text}>/echoes-init</text>
126
+ <text fg={theme.textMuted}> Create vault</text>
127
+ </box>
128
+
129
+ <box paddingX={1} paddingY={0}>
130
+ <text fg={theme.text}>/echoes-start</text>
131
+ <text fg={theme.textMuted}> Restore context</text>
132
+ </box>
133
+
134
+ <box paddingX={1} paddingY={0}>
135
+ <text fg={theme.text}>/echoes-end</text>
136
+ <text fg={theme.textMuted}> Save session</text>
137
+ </box>
15
138
 
16
- <text fg={theme.secondary}>• Start Session</text>
17
- <text fg={theme.accent}>• End Session</text>
18
- <text fg={theme.error}>• Init</text>
19
- <text fg={theme.warning}>• Status</text>
20
- <text fg={theme.success}>• Success</text>
21
- <text fg={theme.info}>• Info</text>
22
- <text fg={theme.textMuted}>• Muted</text>
139
+ <box paddingX={1} paddingY={0}>
140
+ <text fg={theme.text}>/echoes-status</text>
141
+ <text fg={theme.textMuted}> Vault health</text>
23
142
  </box>
143
+ </box>
24
144
  )
25
145
  },
26
146
  },
27
147
  })
28
148
  }
29
149
 
30
- export default { id: "echoes-vault-ui", tui }
150
+ export default { id: "echoes-vault-sidebar", tui }