pantheon-opencode 1.0.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.
Files changed (128) hide show
  1. package/AGENTS.md +37 -0
  2. package/LICENSE +21 -0
  3. package/README.md +1013 -0
  4. package/bin/pantheon-init.mjs +183 -0
  5. package/commands/pantheon-audit.md +25 -0
  6. package/commands/pantheon-bg.md +10 -0
  7. package/commands/pantheon-consolidate.md +11 -0
  8. package/commands/pantheon-deepwork.md +128 -0
  9. package/commands/pantheon-doc.md +10 -0
  10. package/commands/pantheon-focus.md +9 -0
  11. package/commands/pantheon-forget.md +58 -0
  12. package/commands/pantheon-hash.md +11 -0
  13. package/commands/pantheon-optimize.md +79 -0
  14. package/commands/pantheon-remember.md +44 -0
  15. package/commands/pantheon-search.md +48 -0
  16. package/commands/pantheon-status.md +71 -0
  17. package/commands/pantheon-todo.md +11 -0
  18. package/commands/pantheon.md +49 -0
  19. package/docs/AGENT-MCP.md +194 -0
  20. package/docs/ARCHITECTURE.md +384 -0
  21. package/docs/BRANCH-PROTECTION.md +142 -0
  22. package/docs/INDEX.md +81 -0
  23. package/docs/INSTALLATION.md +217 -0
  24. package/docs/MCP.md +238 -0
  25. package/docs/MEMORY.md +471 -0
  26. package/docs/MIGRATION-MEMORY-BANK.md +139 -0
  27. package/docs/PLATFORMS.md +5 -0
  28. package/docs/QUICKSTART.md +49 -0
  29. package/docs/README.md +18 -0
  30. package/docs/RELEASING.md +256 -0
  31. package/docs/SETUP.md +5 -0
  32. package/docs/UPGRADING.md +41 -0
  33. package/docs/mcp-recommendations.md +439 -0
  34. package/docs/mcp-tools.md +156 -0
  35. package/docs/mcp-user-guide.md +204 -0
  36. package/docs/persistence-mcp.md +111 -0
  37. package/package.json +72 -0
  38. package/pantheon.schema.json +158 -0
  39. package/scripts/__init__.py +0 -0
  40. package/scripts/_pantheon_paths.py +68 -0
  41. package/scripts/check-version-consistency.sh +23 -0
  42. package/scripts/code_mode_server.py +202 -0
  43. package/scripts/doctor.mjs +763 -0
  44. package/scripts/generate-prompts.sh +222 -0
  45. package/scripts/generate-routing-docs.mjs +104 -0
  46. package/scripts/hash_verify.py +192 -0
  47. package/scripts/init-pantheon-mcp.sh +118 -0
  48. package/scripts/install/agents-md.mjs +214 -0
  49. package/scripts/install/health-check.mjs +196 -0
  50. package/scripts/install/migrate.mjs +209 -0
  51. package/scripts/install/opencode.mjs +645 -0
  52. package/scripts/install/shared.mjs +655 -0
  53. package/scripts/install/venv.mjs +116 -0
  54. package/scripts/install-mcp.mjs +885 -0
  55. package/scripts/install.mjs +26 -0
  56. package/scripts/manifest.mjs +622 -0
  57. package/scripts/mcp_persistence_server.py +459 -0
  58. package/scripts/mcp_resources_server.py +206 -0
  59. package/scripts/memory_cache.py +78 -0
  60. package/scripts/memory_mcp_server.py +605 -0
  61. package/scripts/paths.py +64 -0
  62. package/scripts/prune_context.py +72 -0
  63. package/scripts/release-bundle.mjs +109 -0
  64. package/scripts/scrub-secrets.py +282 -0
  65. package/scripts/scrub_secrets.py +281 -0
  66. package/scripts/test-context-compression.sh +166 -0
  67. package/scripts/themis_heuristic_scan.py +287 -0
  68. package/scripts/todo_enforcer.py +242 -0
  69. package/scripts/uninstall.mjs +1057 -0
  70. package/scripts/validate-routing.mjs +160 -0
  71. package/scripts/validate_agent_frontmatter.py +226 -0
  72. package/scripts/versioning.mjs +254 -0
  73. package/skills-lock.json +16 -0
  74. package/src/agents/aphrodite.md +162 -0
  75. package/src/agents/apollo.md +109 -0
  76. package/src/agents/athena.md +226 -0
  77. package/src/agents/demeter.md +146 -0
  78. package/src/agents/gaia.md +82 -0
  79. package/src/agents/hephaestus.md +105 -0
  80. package/src/agents/hermes.md +302 -0
  81. package/src/agents/iris.md +99 -0
  82. package/src/agents/mnemosyne.md +226 -0
  83. package/src/agents/nyx.md +87 -0
  84. package/src/agents/prometheus.md +199 -0
  85. package/src/agents/talos.md +93 -0
  86. package/src/agents/themis.md +187 -0
  87. package/src/agents/zeus.md +209 -0
  88. package/src/instructions/agent-return-format.instructions.md +26 -0
  89. package/src/instructions/backend-standards.instructions.md +45 -0
  90. package/src/instructions/documentation-standards.instructions.md +53 -0
  91. package/src/instructions/frontend-standards.instructions.md +46 -0
  92. package/src/instructions/memory-protocol.instructions.md +67 -0
  93. package/src/instructions/yagni.instructions.md +21 -0
  94. package/src/instructions/zeus-anti-stall.instructions.md +72 -0
  95. package/src/instructions/zeus-communication-rules.instructions.md +15 -0
  96. package/src/instructions/zeus-council-synthesis.instructions.md +105 -0
  97. package/src/instructions/zeus-timeout-retry.instructions.md +127 -0
  98. package/src/mcp/_pantheon_paths.py +67 -0
  99. package/src/mcp/code_mode_server.py +202 -0
  100. package/src/mcp/init-pantheon-mcp.sh +118 -0
  101. package/src/mcp/install-mcp.mjs +885 -0
  102. package/src/mcp/mcp_persistence_server.py +458 -0
  103. package/src/mcp/mcp_resources_server.py +205 -0
  104. package/src/mcp/memory_mcp_server.py +604 -0
  105. package/src/mcp/requirements-mcp-core.txt +5 -0
  106. package/src/mcp/requirements-mcp.txt +5 -0
  107. package/src/plugin.ts +19 -0
  108. package/src/plugins/tui/dist/tui.js +143 -0
  109. package/src/plugins/tui/dist/tui.tsx +144 -0
  110. package/src/plugins/tui/package.json +32 -0
  111. package/src/plugins/tui/src/index.tsx +144 -0
  112. package/src/plugins/tui/tsdown.config.ts +22 -0
  113. package/src/routing.yml +499 -0
  114. package/src/skills/README.md +230 -0
  115. package/src/skills/agent-coordination/SKILL.md +95 -0
  116. package/src/skills/artifact-management/SKILL.md +118 -0
  117. package/src/skills/auto-continue/SKILL.md +280 -0
  118. package/src/skills/code-review-checklist/SKILL.md +139 -0
  119. package/src/skills/context-compression/SKILL.md +861 -0
  120. package/src/skills/git-workflow-and-versioning/SKILL.md +32 -0
  121. package/src/skills/incremental-implementation/SKILL.md +27 -0
  122. package/src/skills/memory-bank/SKILL.md +165 -0
  123. package/src/skills/orchestration-workflow/SKILL.md +311 -0
  124. package/src/skills/security-hardening/SKILL.md +36 -0
  125. package/src/skills/session-goal/SKILL.md +138 -0
  126. package/src/skills/spec-driven-development/SKILL.md +23 -0
  127. package/src/skills/tdd-with-agents/SKILL.md +170 -0
  128. package/src/skills/visual-review-pipeline/SKILL.md +200 -0
@@ -0,0 +1,143 @@
1
+ // src/index.tsx
2
+ import { createMemo, createSignal, Show, For } from "solid-js";
3
+ import { jsx, jsxs } from "@opentui/solid/jsx-runtime";
4
+ async function readVersion(api) {
5
+ try {
6
+ const wt = api.state.path?.worktree ?? "";
7
+ const fp = wt ? `${wt}/package.json` : "package.json";
8
+ const r = await api.client.file.read({ query: { path: fp } });
9
+ const m = String(r?.content ?? "").match(/"version":\s*"([^"]+)"/);
10
+ if (m?.[1]) return m[1];
11
+ } catch {
12
+ }
13
+ return "5.0.0";
14
+ }
15
+ var AGENTS = [
16
+ "zeus",
17
+ "athena",
18
+ "apollo",
19
+ "hermes",
20
+ "aphrodite",
21
+ "demeter",
22
+ "themis",
23
+ "prometheus",
24
+ "hephaestus",
25
+ "nyx",
26
+ "gaia",
27
+ "iris",
28
+ "mnemosyne",
29
+ "talos"
30
+ ];
31
+ var CMDS = [
32
+ "/pantheon",
33
+ "/pantheon-status",
34
+ "/pantheon-audit",
35
+ "/pantheon-bg",
36
+ "/pantheon-deepwork",
37
+ "/pantheon-focus",
38
+ "/pantheon-remember",
39
+ "/pantheon-search",
40
+ "/pantheon-forget"
41
+ ];
42
+ function PantheonPanel(props) {
43
+ const [showSub, setShowSub] = createSignal(false);
44
+ const [showCmd, setShowCmd] = createSignal(false);
45
+ const [showAg, setShowAg] = createSignal(false);
46
+ const [showCfg, setShowCfg] = createSignal(false);
47
+ const [showMem, setShowMem] = createSignal(false);
48
+ const branch = createMemo(() => {
49
+ const b = props.api.state.vcs?.branch;
50
+ return b ? `\u2387 ${b}` : null;
51
+ });
52
+ return /* @__PURE__ */ jsxs("box", { flexDirection: "column", width: "100%", children: [
53
+ /* @__PURE__ */ jsxs("text", { fg: props.api.theme.current.accent, attributes: { bold: true }, children: [
54
+ "Pantheon v",
55
+ props.version
56
+ ] }),
57
+ /* @__PURE__ */ jsx(Show, { when: branch(), children: (b) => /* @__PURE__ */ jsx("box", { marginTop: 1, children: /* @__PURE__ */ jsx("text", { fg: props.api.theme.current.textMuted, children: b() }) }) }),
58
+ /* @__PURE__ */ jsxs("box", { marginTop: 0, onMouseDown: () => setShowSub((x) => !x), children: [
59
+ /* @__PURE__ */ jsxs("text", { fg: props.api.theme.current.text, attributes: { bold: true }, children: [
60
+ showSub() ? "\u25BC " : "\u25B6 ",
61
+ "Subagents"
62
+ ] }),
63
+ /* @__PURE__ */ jsxs("text", { fg: props.api.theme.current.textMuted, children: [
64
+ " (",
65
+ props.api.state.session.count(),
66
+ ")"
67
+ ] })
68
+ ] }),
69
+ /* @__PURE__ */ jsx(Show, { when: showSub(), children: /* @__PURE__ */ jsx("box", { marginLeft: 1, children: /* @__PURE__ */ jsxs("text", { fg: props.api.theme.current.textMuted, children: [
70
+ "sessions: ",
71
+ props.api.state.session.count()
72
+ ] }) }) }),
73
+ /* @__PURE__ */ jsxs("box", { marginTop: 0, onMouseDown: () => setShowCmd((x) => !x), children: [
74
+ /* @__PURE__ */ jsxs("text", { fg: props.api.theme.current.text, attributes: { bold: true }, children: [
75
+ showCmd() ? "\u25BC " : "\u25B6 ",
76
+ "Commands"
77
+ ] }),
78
+ /* @__PURE__ */ jsxs("text", { fg: props.api.theme.current.textMuted, children: [
79
+ " (",
80
+ CMDS.length,
81
+ ")"
82
+ ] })
83
+ ] }),
84
+ /* @__PURE__ */ jsx(Show, { when: showCmd(), children: /* @__PURE__ */ jsx("box", { marginLeft: 1, flexDirection: "column", children: /* @__PURE__ */ jsx(For, { each: CMDS, children: (cmd) => /* @__PURE__ */ jsxs("text", { fg: props.api.theme.current.textMuted, children: [
85
+ "\xB7",
86
+ " ",
87
+ cmd
88
+ ] }) }) }) }),
89
+ /* @__PURE__ */ jsxs("box", { marginTop: 0, onMouseDown: () => setShowAg((x) => !x), children: [
90
+ /* @__PURE__ */ jsxs("text", { fg: props.api.theme.current.text, attributes: { bold: true }, children: [
91
+ showAg() ? "\u25BC " : "\u25B6 ",
92
+ "Agents"
93
+ ] }),
94
+ /* @__PURE__ */ jsxs("text", { fg: props.api.theme.current.textMuted, children: [
95
+ " (",
96
+ AGENTS.length,
97
+ ")"
98
+ ] })
99
+ ] }),
100
+ /* @__PURE__ */ jsx(Show, { when: showAg(), children: /* @__PURE__ */ jsx("box", { marginLeft: 1, flexDirection: "column", children: /* @__PURE__ */ jsx(For, { each: AGENTS, children: (a) => /* @__PURE__ */ jsxs("text", { fg: props.api.theme.current.textMuted, children: [
101
+ "\xB7",
102
+ " ",
103
+ a
104
+ ] }) }) }) }),
105
+ /* @__PURE__ */ jsx("box", { marginTop: 0, onMouseDown: () => setShowCfg((x) => !x), children: /* @__PURE__ */ jsxs("text", { fg: props.api.theme.current.text, attributes: { bold: true }, children: [
106
+ showCfg() ? "\u25BC " : "\u25B6 ",
107
+ "Config"
108
+ ] }) }),
109
+ /* @__PURE__ */ jsx(Show, { when: showCfg(), children: /* @__PURE__ */ jsxs("box", { marginLeft: 1, flexDirection: "column", children: [
110
+ /* @__PURE__ */ jsxs("text", { fg: props.api.theme.current.textMuted, children: [
111
+ "MCPs: ",
112
+ props.api.state.config?.mcp ? Object.keys(props.api.state.config.mcp).length : 0
113
+ ] }),
114
+ /* @__PURE__ */ jsxs("text", { fg: props.api.theme.current.textMuted, children: [
115
+ "Compaction: ",
116
+ props.api.state.config?.compaction?.auto ? "ON" : "OFF"
117
+ ] })
118
+ ] }) }),
119
+ /* @__PURE__ */ jsx("box", { marginTop: 0, onMouseDown: () => setShowMem((x) => !x), children: /* @__PURE__ */ jsxs("text", { fg: props.api.theme.current.text, attributes: { bold: true }, children: [
120
+ showMem() ? "\u25BC " : "\u25B6 ",
121
+ "Memory"
122
+ ] }) }),
123
+ /* @__PURE__ */ jsx(Show, { when: showMem(), children: /* @__PURE__ */ jsx("box", { marginLeft: 1, children: /* @__PURE__ */ jsx("text", { fg: props.api.theme.current.textMuted, children: props.api.state.memory?.entries > 0 ? `Entries: ${props.api.state.memory.entries}` : "(no data)" }) }) })
124
+ ] });
125
+ }
126
+ function createSlot(api) {
127
+ const version = createMemo(() => readVersion(api));
128
+ return {
129
+ order: 900,
130
+ slots: {
131
+ sidebar_content(_ctx, input) {
132
+ return /* @__PURE__ */ jsx(PantheonPanel, { api, version: version() });
133
+ }
134
+ }
135
+ };
136
+ }
137
+ var tui = async (api) => {
138
+ api.slots.register(createSlot(api));
139
+ };
140
+ var index_default = { id: "pantheon.tui", tui };
141
+ export {
142
+ index_default as default
143
+ };
@@ -0,0 +1,144 @@
1
+ /** @jsxImportSource @opentui/solid */
2
+ import type { TuiPlugin, TuiPluginApi, TuiPluginModule, TuiSlotContext, TuiSlotPlugin } from '@opencode-ai/plugin/tui'
3
+ import type { JSX } from '@opentui/solid'
4
+ import { createMemo, createSignal, Show, For } from 'solid-js'
5
+
6
+ const AGENTS = [
7
+ 'zeus', 'athena', 'apollo', 'hermes', 'aphrodite',
8
+ 'demeter', 'themis', 'prometheus', 'hephaestus',
9
+ 'nyx', 'gaia', 'iris', 'mnemosyne', 'talos',
10
+ ] as const
11
+
12
+ const CMDS = [
13
+ '/pantheon', '/pantheon-status', '/pantheon-audit',
14
+ '/pantheon-bg', '/pantheon-deepwork', '/pantheon-focus',
15
+ '/pantheon-optimize', '/pantheon-doc',
16
+ '/pantheon-remember', '/pantheon-search', '/pantheon-forget',
17
+ '/pantheon-consolidate', '/pantheon-todo', '/pantheon-hash',
18
+ ] as const
19
+
20
+ function PantheonPanel(props: { api: TuiPluginApi; version: string }): JSX.Element {
21
+ const [showSub, setShowSub] = createSignal(false)
22
+ const [showCmd, setShowCmd] = createSignal(false)
23
+ const [showAg, setShowAg] = createSignal(false)
24
+ const [showCfg, setShowCfg] = createSignal(false)
25
+ const [showMem, setShowMem] = createSignal(false)
26
+
27
+ const branch = createMemo(() => {
28
+ const b = props.api.state.vcs?.branch
29
+ return b ? `\u2387 ${b}` : null
30
+ })
31
+
32
+ const mem = (props.api.state as any).memory
33
+ const cfg = props.api.state.config
34
+
35
+ return (
36
+ <box flexDirection="column" width="100%">
37
+ <text fg={props.api.theme.current.accent} attributes={{ bold: true }}>
38
+ Pantheon v{props.version}
39
+ </text>
40
+
41
+ <Show when={branch()}>
42
+ {(b) => <box marginTop={1}><text fg={props.api.theme.current.textMuted}>{b()}</text></box>}
43
+ </Show>
44
+
45
+ {/* Sessions — total historico (API nao distingue ativas) */}
46
+ <box marginTop={0} onMouseDown={() => setShowSub((x) => !x)}>
47
+ <text fg={props.api.theme.current.text} attributes={{ bold: true }}>
48
+ {showSub() ? '\u25bc ' : '\u25b6 '}Sessions
49
+ </text>
50
+ <text fg={props.api.theme.current.textMuted}>
51
+ ({(props.api.state as any).session?.count?.() ?? '?'} total)
52
+ </text>
53
+ </box>
54
+
55
+ {/* Commands */}
56
+ <box marginTop={0} onMouseDown={() => setShowCmd((x) => !x)}>
57
+ <text fg={props.api.theme.current.text} attributes={{ bold: true }}>
58
+ {showCmd() ? '\u25bc ' : '\u25b6 '}Commands
59
+ </text>
60
+ <text fg={props.api.theme.current.textMuted}> ({CMDS.length})</text>
61
+ </box>
62
+ <Show when={showCmd()}>
63
+ <box marginLeft={1} flexDirection="column">
64
+ <For each={CMDS}>
65
+ {(cmd) => <text fg={props.api.theme.current.textMuted}>{'\u00b7'} {cmd}</text>}
66
+ </For>
67
+ </box>
68
+ </Show>
69
+
70
+ {/* Agents */}
71
+ <box marginTop={0} onMouseDown={() => setShowAg((x) => !x)}>
72
+ <text fg={props.api.theme.current.text} attributes={{ bold: true }}>
73
+ {showAg() ? '\u25bc ' : '\u25b6 '}Agents
74
+ </text>
75
+ <text fg={props.api.theme.current.textMuted}> ({AGENTS.length})</text>
76
+ </box>
77
+ <Show when={showAg()}>
78
+ <box marginLeft={1} flexDirection="column">
79
+ <For each={AGENTS}>
80
+ {(a) => <text fg={props.api.theme.current.textMuted}>{'\u00b7'} {a}</text>}
81
+ </For>
82
+ </box>
83
+ </Show>
84
+
85
+ {/* Config */}
86
+ <box marginTop={0} onMouseDown={() => setShowCfg((x) => !x)}>
87
+ <text fg={props.api.theme.current.text} attributes={{ bold: true }}>
88
+ {showCfg() ? '\u25bc ' : '\u25b6 '}Config
89
+ </text>
90
+ </box>
91
+ <Show when={showCfg()}>
92
+ <box marginLeft={1} flexDirection="column">
93
+ <text fg={props.api.theme.current.textMuted}>
94
+ MCPs: {cfg?.mcp ? Object.keys(cfg.mcp).length : 0}
95
+ </text>
96
+ <text fg={props.api.theme.current.textMuted}>
97
+ Compaction: {cfg?.compaction?.auto ? 'ON' : 'OFF'}
98
+ </text>
99
+ </box>
100
+ </Show>
101
+
102
+ {/* Memory */}
103
+ <box marginTop={0} onMouseDown={() => setShowMem((x) => !x)}>
104
+ <text fg={props.api.theme.current.text} attributes={{ bold: true }}>
105
+ {showMem() ? '\u25bc ' : '\u25b6 '}Memory
106
+ </text>
107
+ </box>
108
+ <Show when={showMem()}>
109
+ <box marginLeft={1}>
110
+ <text fg={props.api.theme.current.textMuted}>
111
+ {mem?.entries > 0 ? `Entries: ${mem.entries}` : '(no data)'}
112
+ </text>
113
+ </box>
114
+ </Show>
115
+ </box>
116
+ )
117
+ }
118
+
119
+ function createSlot(api: TuiPluginApi, version: string): TuiSlotPlugin {
120
+ return {
121
+ order: 900,
122
+ slots: {
123
+ sidebar_content(_ctx: TuiSlotContext, _input: { session_id: string }): JSX.Element {
124
+ return <PantheonPanel api={api} version={version} />
125
+ },
126
+ },
127
+ }
128
+ }
129
+
130
+ const tui: TuiPlugin = async (api: TuiPluginApi) => {
131
+ // Read version ONCE at startup (sincrono, evitando Promise)
132
+ let version = '5.0.0'
133
+ try {
134
+ const wt = api.state.path?.worktree ?? ''
135
+ const fp = wt ? `${wt}/package.json` : 'package.json'
136
+ const r = await api.client.file.read({ query: { path: fp } })
137
+ const m = String(r?.content ?? '').match(/"version":\s*"([^"]+)"/)
138
+ if (m?.[1]) version = m[1]
139
+ } catch { /* fallback */ }
140
+
141
+ api.slots.register(createSlot(api, version))
142
+ }
143
+
144
+ export default { id: 'pantheon.tui', tui } as TuiPluginModule & { id: string }
@@ -0,0 +1,32 @@
1
+ {
2
+ "name": "pantheon-tui",
3
+ "type": "module",
4
+ "version": "1.0.0",
5
+ "description": "Pantheon TUI sidebar plugin \u2014 agent status, commands, and system info",
6
+ "license": "MIT",
7
+ "exports": {
8
+ "./tui": "./dist/tui.tsx"
9
+ },
10
+ "files": [
11
+ "dist",
12
+ "src"
13
+ ],
14
+ "scripts": {
15
+ "build": "mkdir -p dist && cp src/index.tsx dist/tui.tsx",
16
+ "typecheck": "tsc --noEmit"
17
+ },
18
+ "peerDependencies": {
19
+ "@opencode-ai/plugin": ">=1.14.0",
20
+ "@opencode-ai/sdk": ">=1.14.0",
21
+ "@opentui/core": ">=0.2.0",
22
+ "@opentui/solid": ">=0.2.0",
23
+ "solid-js": ">=1.9.0"
24
+ },
25
+ "devDependencies": {},
26
+ "dependencies": {
27
+ "@opencode-ai/plugin": "^1.14.0",
28
+ "@opentui/core": "^0.2.0",
29
+ "@opentui/solid": "^0.2.0",
30
+ "solid-js": "^1.9.0"
31
+ }
32
+ }
@@ -0,0 +1,144 @@
1
+ /** @jsxImportSource @opentui/solid */
2
+ import type { TuiPlugin, TuiPluginApi, TuiPluginModule, TuiSlotContext, TuiSlotPlugin } from '@opencode-ai/plugin/tui'
3
+ import type { JSX } from '@opentui/solid'
4
+ import { createMemo, createSignal, Show, For } from 'solid-js'
5
+
6
+ const AGENTS = [
7
+ 'zeus', 'athena', 'apollo', 'hermes', 'aphrodite',
8
+ 'demeter', 'themis', 'prometheus', 'hephaestus',
9
+ 'nyx', 'gaia', 'iris', 'mnemosyne', 'talos',
10
+ ] as const
11
+
12
+ const CMDS = [
13
+ '/pantheon', '/pantheon-status', '/pantheon-audit',
14
+ '/pantheon-bg', '/pantheon-deepwork', '/pantheon-focus',
15
+ '/pantheon-optimize', '/pantheon-doc',
16
+ '/pantheon-remember', '/pantheon-search', '/pantheon-forget',
17
+ '/pantheon-consolidate', '/pantheon-todo', '/pantheon-hash',
18
+ ] as const
19
+
20
+ function PantheonPanel(props: { api: TuiPluginApi; version: string }): JSX.Element {
21
+ const [showSub, setShowSub] = createSignal(false)
22
+ const [showCmd, setShowCmd] = createSignal(false)
23
+ const [showAg, setShowAg] = createSignal(false)
24
+ const [showCfg, setShowCfg] = createSignal(false)
25
+ const [showMem, setShowMem] = createSignal(false)
26
+
27
+ const branch = createMemo(() => {
28
+ const b = props.api.state.vcs?.branch
29
+ return b ? `\u2387 ${b}` : null
30
+ })
31
+
32
+ const mem = (props.api.state as any).memory
33
+ const cfg = props.api.state.config
34
+
35
+ return (
36
+ <box flexDirection="column" width="100%">
37
+ <text fg={props.api.theme.current.accent} attributes={{ bold: true }}>
38
+ Pantheon v{props.version}
39
+ </text>
40
+
41
+ <Show when={branch()}>
42
+ {(b) => <box marginTop={1}><text fg={props.api.theme.current.textMuted}>{b()}</text></box>}
43
+ </Show>
44
+
45
+ {/* Sessions — total historico (API nao distingue ativas) */}
46
+ <box marginTop={0} onMouseDown={() => setShowSub((x) => !x)}>
47
+ <text fg={props.api.theme.current.text} attributes={{ bold: true }}>
48
+ {showSub() ? '\u25bc ' : '\u25b6 '}Sessions
49
+ </text>
50
+ <text fg={props.api.theme.current.textMuted}>
51
+ ({(props.api.state as any).session?.count?.() ?? '?'} total)
52
+ </text>
53
+ </box>
54
+
55
+ {/* Commands */}
56
+ <box marginTop={0} onMouseDown={() => setShowCmd((x) => !x)}>
57
+ <text fg={props.api.theme.current.text} attributes={{ bold: true }}>
58
+ {showCmd() ? '\u25bc ' : '\u25b6 '}Commands
59
+ </text>
60
+ <text fg={props.api.theme.current.textMuted}> ({CMDS.length})</text>
61
+ </box>
62
+ <Show when={showCmd()}>
63
+ <box marginLeft={1} flexDirection="column">
64
+ <For each={CMDS}>
65
+ {(cmd) => <text fg={props.api.theme.current.textMuted}>{'\u00b7'} {cmd}</text>}
66
+ </For>
67
+ </box>
68
+ </Show>
69
+
70
+ {/* Agents */}
71
+ <box marginTop={0} onMouseDown={() => setShowAg((x) => !x)}>
72
+ <text fg={props.api.theme.current.text} attributes={{ bold: true }}>
73
+ {showAg() ? '\u25bc ' : '\u25b6 '}Agents
74
+ </text>
75
+ <text fg={props.api.theme.current.textMuted}> ({AGENTS.length})</text>
76
+ </box>
77
+ <Show when={showAg()}>
78
+ <box marginLeft={1} flexDirection="column">
79
+ <For each={AGENTS}>
80
+ {(a) => <text fg={props.api.theme.current.textMuted}>{'\u00b7'} {a}</text>}
81
+ </For>
82
+ </box>
83
+ </Show>
84
+
85
+ {/* Config */}
86
+ <box marginTop={0} onMouseDown={() => setShowCfg((x) => !x)}>
87
+ <text fg={props.api.theme.current.text} attributes={{ bold: true }}>
88
+ {showCfg() ? '\u25bc ' : '\u25b6 '}Config
89
+ </text>
90
+ </box>
91
+ <Show when={showCfg()}>
92
+ <box marginLeft={1} flexDirection="column">
93
+ <text fg={props.api.theme.current.textMuted}>
94
+ MCPs: {cfg?.mcp ? Object.keys(cfg.mcp).length : 0}
95
+ </text>
96
+ <text fg={props.api.theme.current.textMuted}>
97
+ Compaction: {cfg?.compaction?.auto ? 'ON' : 'OFF'}
98
+ </text>
99
+ </box>
100
+ </Show>
101
+
102
+ {/* Memory */}
103
+ <box marginTop={0} onMouseDown={() => setShowMem((x) => !x)}>
104
+ <text fg={props.api.theme.current.text} attributes={{ bold: true }}>
105
+ {showMem() ? '\u25bc ' : '\u25b6 '}Memory
106
+ </text>
107
+ </box>
108
+ <Show when={showMem()}>
109
+ <box marginLeft={1}>
110
+ <text fg={props.api.theme.current.textMuted}>
111
+ {mem?.entries > 0 ? `Entries: ${mem.entries}` : '(no data)'}
112
+ </text>
113
+ </box>
114
+ </Show>
115
+ </box>
116
+ )
117
+ }
118
+
119
+ function createSlot(api: TuiPluginApi, version: string): TuiSlotPlugin {
120
+ return {
121
+ order: 900,
122
+ slots: {
123
+ sidebar_content(_ctx: TuiSlotContext, _input: { session_id: string }): JSX.Element {
124
+ return <PantheonPanel api={api} version={version} />
125
+ },
126
+ },
127
+ }
128
+ }
129
+
130
+ const tui: TuiPlugin = async (api: TuiPluginApi) => {
131
+ // Read version ONCE at startup (sincrono, evitando Promise)
132
+ let version = '5.0.0'
133
+ try {
134
+ const wt = api.state.path?.worktree ?? ''
135
+ const fp = wt ? `${wt}/package.json` : 'package.json'
136
+ const r = await api.client.file.read({ query: { path: fp } })
137
+ const m = String(r?.content ?? '').match(/"version":\s*"([^"]+)"/)
138
+ if (m?.[1]) version = m[1]
139
+ } catch { /* fallback */ }
140
+
141
+ api.slots.register(createSlot(api, version))
142
+ }
143
+
144
+ export default { id: 'pantheon.tui', tui } as TuiPluginModule & { id: string }
@@ -0,0 +1,22 @@
1
+ import { defineConfig } from 'tsdown'
2
+ import solid from 'rolldown-plugin-solid'
3
+
4
+ export default defineConfig({
5
+ entry: { tui: 'src/index.tsx' },
6
+ format: ['esm'],
7
+ platform: 'node',
8
+ outDir: 'dist',
9
+ clean: true,
10
+ outExtensions: () => ({ js: '.js' }),
11
+ plugins: [
12
+ solid({
13
+ solid: {
14
+ moduleName: '@opentui/solid',
15
+ generate: 'universal',
16
+ },
17
+ }),
18
+ ],
19
+ deps: {
20
+ neverBundle: [/^@opencode-ai\//, /^@opentui\//, /^solid-js/],
21
+ },
22
+ })