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.
- package/AGENTS.md +37 -0
- package/LICENSE +21 -0
- package/README.md +1013 -0
- package/bin/pantheon-init.mjs +183 -0
- package/commands/pantheon-audit.md +25 -0
- package/commands/pantheon-bg.md +10 -0
- package/commands/pantheon-consolidate.md +11 -0
- package/commands/pantheon-deepwork.md +128 -0
- package/commands/pantheon-doc.md +10 -0
- package/commands/pantheon-focus.md +9 -0
- package/commands/pantheon-forget.md +58 -0
- package/commands/pantheon-hash.md +11 -0
- package/commands/pantheon-optimize.md +79 -0
- package/commands/pantheon-remember.md +44 -0
- package/commands/pantheon-search.md +48 -0
- package/commands/pantheon-status.md +71 -0
- package/commands/pantheon-todo.md +11 -0
- package/commands/pantheon.md +49 -0
- package/docs/AGENT-MCP.md +194 -0
- package/docs/ARCHITECTURE.md +384 -0
- package/docs/BRANCH-PROTECTION.md +142 -0
- package/docs/INDEX.md +81 -0
- package/docs/INSTALLATION.md +217 -0
- package/docs/MCP.md +238 -0
- package/docs/MEMORY.md +471 -0
- package/docs/MIGRATION-MEMORY-BANK.md +139 -0
- package/docs/PLATFORMS.md +5 -0
- package/docs/QUICKSTART.md +49 -0
- package/docs/README.md +18 -0
- package/docs/RELEASING.md +256 -0
- package/docs/SETUP.md +5 -0
- package/docs/UPGRADING.md +41 -0
- package/docs/mcp-recommendations.md +439 -0
- package/docs/mcp-tools.md +156 -0
- package/docs/mcp-user-guide.md +204 -0
- package/docs/persistence-mcp.md +111 -0
- package/package.json +72 -0
- package/pantheon.schema.json +158 -0
- package/scripts/__init__.py +0 -0
- package/scripts/_pantheon_paths.py +68 -0
- package/scripts/check-version-consistency.sh +23 -0
- package/scripts/code_mode_server.py +202 -0
- package/scripts/doctor.mjs +763 -0
- package/scripts/generate-prompts.sh +222 -0
- package/scripts/generate-routing-docs.mjs +104 -0
- package/scripts/hash_verify.py +192 -0
- package/scripts/init-pantheon-mcp.sh +118 -0
- package/scripts/install/agents-md.mjs +214 -0
- package/scripts/install/health-check.mjs +196 -0
- package/scripts/install/migrate.mjs +209 -0
- package/scripts/install/opencode.mjs +645 -0
- package/scripts/install/shared.mjs +655 -0
- package/scripts/install/venv.mjs +116 -0
- package/scripts/install-mcp.mjs +885 -0
- package/scripts/install.mjs +26 -0
- package/scripts/manifest.mjs +622 -0
- package/scripts/mcp_persistence_server.py +459 -0
- package/scripts/mcp_resources_server.py +206 -0
- package/scripts/memory_cache.py +78 -0
- package/scripts/memory_mcp_server.py +605 -0
- package/scripts/paths.py +64 -0
- package/scripts/prune_context.py +72 -0
- package/scripts/release-bundle.mjs +109 -0
- package/scripts/scrub-secrets.py +282 -0
- package/scripts/scrub_secrets.py +281 -0
- package/scripts/test-context-compression.sh +166 -0
- package/scripts/themis_heuristic_scan.py +287 -0
- package/scripts/todo_enforcer.py +242 -0
- package/scripts/uninstall.mjs +1057 -0
- package/scripts/validate-routing.mjs +160 -0
- package/scripts/validate_agent_frontmatter.py +226 -0
- package/scripts/versioning.mjs +254 -0
- package/skills-lock.json +16 -0
- package/src/agents/aphrodite.md +162 -0
- package/src/agents/apollo.md +109 -0
- package/src/agents/athena.md +226 -0
- package/src/agents/demeter.md +146 -0
- package/src/agents/gaia.md +82 -0
- package/src/agents/hephaestus.md +105 -0
- package/src/agents/hermes.md +302 -0
- package/src/agents/iris.md +99 -0
- package/src/agents/mnemosyne.md +226 -0
- package/src/agents/nyx.md +87 -0
- package/src/agents/prometheus.md +199 -0
- package/src/agents/talos.md +93 -0
- package/src/agents/themis.md +187 -0
- package/src/agents/zeus.md +209 -0
- package/src/instructions/agent-return-format.instructions.md +26 -0
- package/src/instructions/backend-standards.instructions.md +45 -0
- package/src/instructions/documentation-standards.instructions.md +53 -0
- package/src/instructions/frontend-standards.instructions.md +46 -0
- package/src/instructions/memory-protocol.instructions.md +67 -0
- package/src/instructions/yagni.instructions.md +21 -0
- package/src/instructions/zeus-anti-stall.instructions.md +72 -0
- package/src/instructions/zeus-communication-rules.instructions.md +15 -0
- package/src/instructions/zeus-council-synthesis.instructions.md +105 -0
- package/src/instructions/zeus-timeout-retry.instructions.md +127 -0
- package/src/mcp/_pantheon_paths.py +67 -0
- package/src/mcp/code_mode_server.py +202 -0
- package/src/mcp/init-pantheon-mcp.sh +118 -0
- package/src/mcp/install-mcp.mjs +885 -0
- package/src/mcp/mcp_persistence_server.py +458 -0
- package/src/mcp/mcp_resources_server.py +205 -0
- package/src/mcp/memory_mcp_server.py +604 -0
- package/src/mcp/requirements-mcp-core.txt +5 -0
- package/src/mcp/requirements-mcp.txt +5 -0
- package/src/plugin.ts +19 -0
- package/src/plugins/tui/dist/tui.js +143 -0
- package/src/plugins/tui/dist/tui.tsx +144 -0
- package/src/plugins/tui/package.json +32 -0
- package/src/plugins/tui/src/index.tsx +144 -0
- package/src/plugins/tui/tsdown.config.ts +22 -0
- package/src/routing.yml +499 -0
- package/src/skills/README.md +230 -0
- package/src/skills/agent-coordination/SKILL.md +95 -0
- package/src/skills/artifact-management/SKILL.md +118 -0
- package/src/skills/auto-continue/SKILL.md +280 -0
- package/src/skills/code-review-checklist/SKILL.md +139 -0
- package/src/skills/context-compression/SKILL.md +861 -0
- package/src/skills/git-workflow-and-versioning/SKILL.md +32 -0
- package/src/skills/incremental-implementation/SKILL.md +27 -0
- package/src/skills/memory-bank/SKILL.md +165 -0
- package/src/skills/orchestration-workflow/SKILL.md +311 -0
- package/src/skills/security-hardening/SKILL.md +36 -0
- package/src/skills/session-goal/SKILL.md +138 -0
- package/src/skills/spec-driven-development/SKILL.md +23 -0
- package/src/skills/tdd-with-agents/SKILL.md +170 -0
- 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
|
+
})
|