pantheon-opencode 1.6.0-beta.8 → 1.6.0-beta.9
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/CHANGELOG.md +30 -0
- package/README.md +3 -1
- package/commands/pantheon-audit.md +7 -1
- package/commands/pantheon-consolidate.md +1 -1
- package/commands/pantheon-focus.md +17 -0
- package/package.json +1 -1
- package/plugin.json +1 -1
- package/pyproject.toml +1 -1
- package/scripts/install/opencode.mjs +60 -34
- package/scripts/install/plugin.mjs +43 -9
- package/scripts/sync-artifacts.mjs +1 -0
- package/scripts/sync-tui.mjs +24 -3
- package/skills-lock.json +1 -1
- package/src/agents/mnemosyne.md +4 -11
- package/src/plugins/tui/dist/tui-v2.d.ts +9 -0
- package/src/plugins/tui/dist/tui-v2.d.ts.map +1 -0
- package/src/plugins/tui/dist/tui-v2.js +151 -0
- package/src/plugins/tui/dist/tui-v2.js.map +1 -0
- package/src/plugins/tui/dist/tui.js +4 -4
- package/src/plugins/tui/index-v2.ts +6 -0
- package/src/plugins/tui/package-lock.json +5411 -1292
- package/src/plugins/tui/package.json +10 -7
- package/src/plugins/tui/src/index-v2.tsx +108 -0
- package/src/plugins/tui/src/index.tsx +3 -3
- package/src/plugins/tui/src/opencode-v2.d.ts +13 -0
- package/src/plugins/tui/tsdown.config.ts +2 -2
- package/src/plugins/tui/tui-v2.ts +2 -0
- package/src/plugins/tui/tui.ts +3 -0
- package/src/skills/session-goal/SKILL.md +14 -5
package/CHANGELOG.md
CHANGED
|
@@ -18,6 +18,36 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
|
|
|
18
18
|
|
|
19
19
|
## ✅ Closed Issues
|
|
20
20
|
|
|
21
|
+
## [v1.6.0-beta.9] - 2026-10-12
|
|
22
|
+
|
|
23
|
+
<!-- Add new changes here. Running `node scripts/versioning.mjs apply` will
|
|
24
|
+
move this section to a versioned entry and reset the template below. -->
|
|
25
|
+
|
|
26
|
+
## 🆕 What's New
|
|
27
|
+
|
|
28
|
+
- **Entry point TUI dedicado ao OpenCode V2.** O pacote agora compila e instala
|
|
29
|
+
separadamente os loaders V1/V2, e adiciona `/pantheon-focus` para foco de
|
|
30
|
+
sessão sem depender das goal-tools ausentes no host V2.
|
|
31
|
+
|
|
32
|
+
## 🐞 Fixed
|
|
33
|
+
|
|
34
|
+
- **Instalação V2:** agentes e slash commands de projeto são instalados nos
|
|
35
|
+
diretórios descobertos pelo host; o TUI seleciona o bundle da geração correta
|
|
36
|
+
e o estado dos componentes só é marcado como instalado após sucesso.
|
|
37
|
+
- **`/pantheon-audit`:** inclui o scanner heurístico no pacote e localiza a cópia
|
|
38
|
+
instalada antes de executar a primeira camada.
|
|
39
|
+
- **`/pantheon-consolidate`:** delega a consolidação ao agente Mnemosyne, dono
|
|
40
|
+
da qualidade do banco de memória.
|
|
41
|
+
|
|
42
|
+
## ⚠️ Known Issues
|
|
43
|
+
|
|
44
|
+
- **Sidebar V2 na sessão inicial:** a captura do TUI recém-aberto ainda não
|
|
45
|
+
mostra o conteúdo Pantheon antes do primeiro prompt; validar o render inicial
|
|
46
|
+
interativo continua sendo um gate aberto para a beta.
|
|
47
|
+
- **Goal persistente no OpenCode V2:** as goal-tools não fazem parte da
|
|
48
|
+
superfície V2 suportada; `/pantheon-focus` não substitui uma goal-tool
|
|
49
|
+
persistente/removível do host.
|
|
50
|
+
|
|
21
51
|
## [v1.6.0-beta.8] - 2026-10-11
|
|
22
52
|
|
|
23
53
|
<!-- Add new changes here. Running `node scripts/versioning.mjs apply` will
|
package/README.md
CHANGED
|
@@ -518,7 +518,9 @@ full `TARGET_SHA`; a second pack is not interchangeable.
|
|
|
518
518
|
|
|
519
519
|
CI also rebuilds the TUI with `npm run build --prefix src/plugins/tui` and
|
|
520
520
|
checks every packaged `dist` artifact byte-for-byte against its checked-in
|
|
521
|
-
version, including final newlines.
|
|
521
|
+
version, including final newlines. The build includes separate V1 and native
|
|
522
|
+
OpenCode V2 TUI entrypoints; `init` selects the entrypoint and sidebar slot API
|
|
523
|
+
for the host generation in use.
|
|
522
524
|
|
|
523
525
|
## Sandbox validation (V2)
|
|
524
526
|
|
|
@@ -15,7 +15,13 @@ agent: "zeus"
|
|
|
15
15
|
## Layers
|
|
16
16
|
|
|
17
17
|
### Layer 1 — Heuristic Scan
|
|
18
|
-
|
|
18
|
+
Resolve the installed helper first (do not assume the current project contains
|
|
19
|
+
Pantheon source). Check, in order: `$OPENCODE_CONFIG_DIR/.opencode/scripts/`,
|
|
20
|
+
`$OPENCODE_CONFIG_DIR/scripts/`, `${XDG_CONFIG_HOME:-$HOME/.config}/opencode/scripts/`,
|
|
21
|
+
`$HOME/.opencode/scripts/`, `.opencode/scripts/`, then
|
|
22
|
+
`$(npm root -g)/pantheon-opencode/scripts/`. Resolve the first existing file to
|
|
23
|
+
an absolute path and run `python3 "$helper" --path="$PWD"`; if none exists,
|
|
24
|
+
report the helper as missing and stop Layer 1 rather than claiming it passed.
|
|
19
25
|
Zero tokens, <2s. Checks: ruff, biome, anti-pattern slop, anti-overengineering (YAGNI), hash-anchored edits. Returns score 0-100 + APPROVED/BLOCKING.
|
|
20
26
|
|
|
21
27
|
### Layer 2 — Themis Deep Review
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: "Set or update this session's working goal"
|
|
3
|
+
agent: zeus
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
Pin `$ARGUMENTS` as the working goal for this conversation. Restate it briefly
|
|
7
|
+
as Goal, Scope, Success Criteria, and Out of Scope, filling only what the user
|
|
8
|
+
actually supplied. Ask one concise question if a missing detail changes the
|
|
9
|
+
work materially.
|
|
10
|
+
|
|
11
|
+
Treat the goal as session context, subordinate to system, developer, and user
|
|
12
|
+
instructions. Keep subsequent planning, delegation, and verification aligned
|
|
13
|
+
with it; flag meaningful scope drift before proceeding.
|
|
14
|
+
|
|
15
|
+
This command is conversation-only. Do not call memory or persistence tools,
|
|
16
|
+
write a file, or claim that the goal survives compaction or a new session. For
|
|
17
|
+
multi-phase work that needs durable checkpoints, use `/pantheon-deepwork`.
|
package/package.json
CHANGED
package/plugin.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pantheon",
|
|
3
3
|
"publisher": "ils15",
|
|
4
|
-
"version": "1.6.0-beta.
|
|
4
|
+
"version": "1.6.0-beta.9",
|
|
5
5
|
"displayName": "Pantheon",
|
|
6
6
|
"description": "Conductor-Delegate orchestration platform with 14 specialized agents, 20 skills, and OpenCode support.",
|
|
7
7
|
"agents": "./src/agents",
|
package/pyproject.toml
CHANGED
|
@@ -56,6 +56,7 @@ import {
|
|
|
56
56
|
writeConfigWithBackup,
|
|
57
57
|
writeIfChanged,
|
|
58
58
|
} from './shared.mjs'
|
|
59
|
+
import { createInitialState, hasState, readState, setComponentState, writeState } from './state.mjs'
|
|
59
60
|
import { strings } from './strings.mjs'
|
|
60
61
|
|
|
61
62
|
import { setupVenv, venvPythonPath } from './venv.mjs'
|
|
@@ -541,15 +542,14 @@ export function isGlobalConfigDir(target) {
|
|
|
541
542
|
* package; the loader must NEVER be pointed at that in-package dir (a package
|
|
542
543
|
* reinstall/upgrade replaces the dir under a live registration and leaves
|
|
543
544
|
* diverging copies loading). Instead the installer always copies it into the
|
|
544
|
-
* config dir's plugins/ dir and
|
|
545
|
+
* config dir's plugins/ dir and uses THAT copy:
|
|
545
546
|
*
|
|
546
|
-
* <configDir>/plugins/pantheon-tui (dist/ + package
|
|
547
|
+
* <configDir>/plugins/pantheon-tui (tui.ts + dist/ + package manifests)
|
|
547
548
|
*
|
|
548
|
-
*
|
|
549
|
-
*
|
|
550
|
-
* exports["./server"] → dist/server.js (no-op server() stub)
|
|
549
|
+
* V1 registers that copy through tui.json. V2 discovers the local plugin's
|
|
550
|
+
* index.ts + tui.ts pair; the V2 shim re-exports dist/tui-v2.js.
|
|
551
551
|
*
|
|
552
|
-
* @param {string} configDir -
|
|
552
|
+
* @param {string} configDir - OpenCode config directory (target for global
|
|
553
553
|
* installs, <target>/.opencode for project installs)
|
|
554
554
|
* @returns {string} absolute path of the copied plugin directory
|
|
555
555
|
*/
|
|
@@ -575,23 +575,20 @@ export function tuiConfigLocations(target) {
|
|
|
575
575
|
}
|
|
576
576
|
|
|
577
577
|
/**
|
|
578
|
-
* Sync the Pantheon TUI plugin
|
|
579
|
-
*
|
|
578
|
+
* Sync the Pantheon TUI plugin payload and V1 registration. V2 discovers the
|
|
579
|
+
* copied local-plugin entrypoints and does not use a project tui.json.
|
|
580
580
|
*
|
|
581
581
|
* Contract (single source of truth):
|
|
582
|
-
* 1. ALWAYS copy src/plugins/tui → <configDir>/plugins/pantheon-tui
|
|
583
|
-
*
|
|
584
|
-
* directory that exists and carries the loader contract (exports →
|
|
585
|
-
* dist/tui.js, dist/server.js). The copy is idempotent: a second run is
|
|
586
|
-
* byte-identical.
|
|
582
|
+
* 1. ALWAYS copy src/plugins/tui → <configDir>/plugins/pantheon-tui with the
|
|
583
|
+
* selected host entrypoints and compiled bundle. The copy is idempotent.
|
|
587
584
|
* 2. Clean stale Pantheon TUI refs from ALL tui.json locations OpenCode
|
|
588
585
|
* loads — ~/.opencode, $XDG_CONFIG_HOME/opencode and
|
|
589
586
|
* <target>/.opencode — covering every old reference shape: dist file
|
|
590
587
|
* paths, in-package src/plugins/tui dirs, bare plugins/pantheon-tui
|
|
591
588
|
* copies, and npx paths. A stale ref left in the non-target location
|
|
592
589
|
* would still be loaded and break the TUI.
|
|
593
|
-
* 3.
|
|
594
|
-
*
|
|
590
|
+
* 3. V1 registers the copied directory in the selected target. V2 relies on
|
|
591
|
+
* local-plugin discovery and does not write a project tui.json entry.
|
|
595
592
|
*
|
|
596
593
|
* @param {string} target - install target directory
|
|
597
594
|
* @param {object} [opts]
|
|
@@ -599,18 +596,19 @@ export function tuiConfigLocations(target) {
|
|
|
599
596
|
* @param {boolean} [opts.dryRun=false]
|
|
600
597
|
* @returns {'created'|'skipped'} status for the target registration
|
|
601
598
|
*/
|
|
602
|
-
export function syncTuiRegistration(
|
|
599
|
+
export function syncTuiRegistration(
|
|
600
|
+
target,
|
|
601
|
+
{ isGlobal = false, dryRun = false, version = 'v1' } = {},
|
|
602
|
+
) {
|
|
603
603
|
const configDir = isGlobal ? target : join(target, '.opencode')
|
|
604
604
|
const targetTuiConfigPath = join(configDir, 'tui.json')
|
|
605
605
|
|
|
606
|
-
// 1.
|
|
607
|
-
// plugins/pantheon-tui.
|
|
608
|
-
// in-package src/plugins/tui) keeps installs hermetic and idempotent:
|
|
609
|
-
// the ref points at a dir that exists and has dist/tui.js.
|
|
606
|
+
// 1. Copy the host-specific plugin into the target config's
|
|
607
|
+
// plugins/pantheon-tui. This keeps the installed entry hermetic.
|
|
610
608
|
const tuiSrcDir = join(ROOT, 'src', 'plugins', 'tui')
|
|
611
609
|
const tuiCopyDir = resolveTuiCopyTarget(configDir)
|
|
612
610
|
if (existsSync(tuiSrcDir)) {
|
|
613
|
-
copyPluginFiles(tuiSrcDir, tuiCopyDir, { dryRun })
|
|
611
|
+
copyPluginFiles(tuiSrcDir, tuiCopyDir, { dryRun, version })
|
|
614
612
|
}
|
|
615
613
|
|
|
616
614
|
// 2. Clean stale Pantheon TUI refs from every location OpenCode reads.
|
|
@@ -626,6 +624,11 @@ export function syncTuiRegistration(target, { isGlobal = false, dryRun = false }
|
|
|
626
624
|
})
|
|
627
625
|
}
|
|
628
626
|
|
|
627
|
+
// OpenCode V2 discovers local plugins from the config plugins directories;
|
|
628
|
+
// its TUI plugin API is exposed by the sibling tui.ts entrypoint. V1 still
|
|
629
|
+
// requires the explicit tui.json registration.
|
|
630
|
+
if (version === 'v2') return 'skipped'
|
|
631
|
+
|
|
629
632
|
// 3. Register the copied directory in the selected target only.
|
|
630
633
|
return registerPlugin(targetTuiConfigPath, tuiCopyDir, { dryRun })
|
|
631
634
|
}
|
|
@@ -862,14 +865,13 @@ export async function installOpenCode(
|
|
|
862
865
|
}
|
|
863
866
|
}
|
|
864
867
|
|
|
865
|
-
//
|
|
866
|
-
//
|
|
867
|
-
//
|
|
868
|
-
//
|
|
869
|
-
// .opencode/agents/ .opencode/skills/ .opencode/commands/
|
|
868
|
+
// V1 project installs use the legacy .opencode/agents layout. OpenCode V2's
|
|
869
|
+
// active config directory is the project root and its agent loader scans
|
|
870
|
+
// <config-dir>/{agent,agents}/**, so V2 project agents must be at ./agents.
|
|
871
|
+
// Global installs are flat for both versions.
|
|
870
872
|
const isGlobal = isGlobalConfigDir(target)
|
|
871
873
|
const _subDir = isGlobal ? '' : '.opencode'
|
|
872
|
-
const agentPrefix = isGlobal ? 'agents' : '.opencode/agents'
|
|
874
|
+
const agentPrefix = isGlobal || version === 'v2' ? 'agents' : '.opencode/agents'
|
|
873
875
|
|
|
874
876
|
configure({ dryRun })
|
|
875
877
|
|
|
@@ -888,7 +890,7 @@ export async function installOpenCode(
|
|
|
888
890
|
stats.errors++
|
|
889
891
|
} else {
|
|
890
892
|
const agentStep = step(S.installingAgents)
|
|
891
|
-
const dstDir =
|
|
893
|
+
const dstDir = join(target, agentPrefix)
|
|
892
894
|
if (!dryRun) mkdirSync(dstDir, { recursive: true })
|
|
893
895
|
if (clean && existsSync(dstDir) && !dryRun) {
|
|
894
896
|
const existing = readdirSync(dstDir)
|
|
@@ -968,9 +970,7 @@ export async function installOpenCode(
|
|
|
968
970
|
// already-installed Pantheon agents, but must not create agents the user
|
|
969
971
|
// did not install. Full agent installs do this in phase 1 above.
|
|
970
972
|
if (!componentSet.has('agents')) {
|
|
971
|
-
const installedAgents =
|
|
972
|
-
? join(target, 'agents')
|
|
973
|
-
: join(target, '.opencode', 'agents')
|
|
973
|
+
const installedAgents = join(target, agentPrefix)
|
|
974
974
|
const sourceAgents = join(ROOT, 'src', 'agents')
|
|
975
975
|
if (existsSync(installedAgents) && existsSync(sourceAgents)) {
|
|
976
976
|
const refreshed = copyAgentPrompts(sourceAgents, installedAgents, dryRun, true)
|
|
@@ -1000,7 +1000,11 @@ export async function installOpenCode(
|
|
|
1000
1000
|
if (componentSet.has('commands')) {
|
|
1001
1001
|
section('\u26A1 Commands')
|
|
1002
1002
|
const srcCmds = join(ROOT, 'commands')
|
|
1003
|
-
|
|
1003
|
+
// V2 project sandboxes use OPENCODE_CONFIG_DIR=<project root>, so OpenCode
|
|
1004
|
+
// discovers custom commands from <target>/commands. V1 project installs
|
|
1005
|
+
// keep the standard .opencode/commands layout; global installs are flat.
|
|
1006
|
+
const commandDir = isGlobal || version === 'v2' ? 'commands' : '.opencode/commands'
|
|
1007
|
+
const dstCmds = join(target, commandDir)
|
|
1004
1008
|
if (existsSync(srcCmds)) {
|
|
1005
1009
|
const cmdResult = syncDir(srcCmds, dstCmds, dryRun, clean, (f) => f.endsWith('.md'))
|
|
1006
1010
|
stats.created += cmdResult.created
|
|
@@ -1025,7 +1029,7 @@ export async function installOpenCode(
|
|
|
1025
1029
|
const dstPluginDir = isGlobal
|
|
1026
1030
|
? join(target, 'plugins', 'pantheon-tui')
|
|
1027
1031
|
: join(target, '.opencode', 'plugins', 'pantheon-tui')
|
|
1028
|
-
const pluginStats = installPlugin(srcPluginDir, dstPluginDir, { dryRun, clean })
|
|
1032
|
+
const pluginStats = installPlugin(srcPluginDir, dstPluginDir, { dryRun, clean, version })
|
|
1029
1033
|
stats.created += pluginStats.created
|
|
1030
1034
|
stats.skipped += pluginStats.skipped
|
|
1031
1035
|
stats.errors += pluginStats.errors
|
|
@@ -1037,7 +1041,7 @@ export async function installOpenCode(
|
|
|
1037
1041
|
if (componentSet.has('plugins')) {
|
|
1038
1042
|
let tuiStatus
|
|
1039
1043
|
try {
|
|
1040
|
-
tuiStatus = syncTuiRegistration(target, { isGlobal, dryRun })
|
|
1044
|
+
tuiStatus = syncTuiRegistration(target, { isGlobal, dryRun, version })
|
|
1041
1045
|
} catch (cause) {
|
|
1042
1046
|
error(`TUI plugin setup failed: ${cause.message}`)
|
|
1043
1047
|
stats.errors++
|
|
@@ -1066,6 +1070,7 @@ export async function installOpenCode(
|
|
|
1066
1070
|
'mcp_persistence.py',
|
|
1067
1071
|
'pantheon_vision.py',
|
|
1068
1072
|
'eval_store.py',
|
|
1073
|
+
'themis_heuristic_scan.py',
|
|
1069
1074
|
]
|
|
1070
1075
|
const srcScriptsDir = join(ROOT, 'scripts')
|
|
1071
1076
|
// Canonical MCP server sources live in src/mcp/. Map them explicitly so the
|
|
@@ -1706,4 +1711,25 @@ export async function installOpenCode(
|
|
|
1706
1711
|
if (stats.errors > 0) {
|
|
1707
1712
|
throw new Error(`installation completed with ${stats.errors} error(s); see output above`)
|
|
1708
1713
|
}
|
|
1714
|
+
|
|
1715
|
+
// Record the component state only after the install has completed. The
|
|
1716
|
+
// postinstall marker can predate `init` and start with every component
|
|
1717
|
+
// pending; leaving it untouched made a healthy beta install look incomplete
|
|
1718
|
+
// to `doctor` forever. Unselected components retain their previous state.
|
|
1719
|
+
if (!dryRun) {
|
|
1720
|
+
const packageVersion = JSON.parse(readFileSync(join(ROOT, 'package.json'), 'utf8')).version
|
|
1721
|
+
let state = readState(target)
|
|
1722
|
+
if (!state && hasState(target)) {
|
|
1723
|
+
throw new Error('Installation state exists but cannot be read; refusing to replace it')
|
|
1724
|
+
}
|
|
1725
|
+
state ??= createInitialState(packageVersion)
|
|
1726
|
+
state.pantheon_version = packageVersion
|
|
1727
|
+
for (const component of ['agents', 'skills', 'plugins', 'runtime']) {
|
|
1728
|
+
if (!componentSet.has(component)) continue
|
|
1729
|
+
const status = component === 'runtime' && !runtimeHealthy ? 'failed' : 'installed'
|
|
1730
|
+
const componentVersion = state.components?.[component]?.version ?? 1
|
|
1731
|
+
setComponentState(state, component, componentVersion, status)
|
|
1732
|
+
}
|
|
1733
|
+
writeState(target, state)
|
|
1734
|
+
}
|
|
1709
1735
|
}
|
|
@@ -8,24 +8,24 @@ import { isAbsolute, join, resolve } from 'node:path'
|
|
|
8
8
|
import { ROOT, writeIfChanged } from './shared.mjs'
|
|
9
9
|
|
|
10
10
|
/**
|
|
11
|
-
* Copy a plugin's runtime payload (the bundled dist/*,
|
|
12
|
-
* package-lock.json) from source to destination.
|
|
13
|
-
*
|
|
14
|
-
*
|
|
11
|
+
* Copy a plugin's runtime payload (the root TUI loader, bundled dist/*,
|
|
12
|
+
* package.json and package-lock.json) from source to destination. The raw TSX
|
|
13
|
+
* implementation is never shipped to the destination; tui.ts only re-exports
|
|
14
|
+
* the host-specific bundle so the local plugin stays hermetic.
|
|
15
15
|
* @param {string} srcDir - Source plugin directory (e.g. ROOT/src/plugins/tui)
|
|
16
16
|
* @param {string} dstDir - Destination plugin directory
|
|
17
17
|
* @param {object} [options]
|
|
18
18
|
* @param {boolean} [options.dryRun=false] - If true, don't write files
|
|
19
|
+
* @param {'v1'|'v2'} [options.version='v1'] - Host plugin generation
|
|
19
20
|
* @returns {{ created: number, skipped: number }}
|
|
20
21
|
*/
|
|
21
|
-
export function copyPluginFiles(srcDir, dstDir, { dryRun = false } = {}) {
|
|
22
|
+
export function copyPluginFiles(srcDir, dstDir, { dryRun = false, version = 'v1' } = {}) {
|
|
22
23
|
const result = { created: 0, skipped: 0 }
|
|
23
24
|
|
|
24
25
|
if (!dryRun) mkdirSync(dstDir, { recursive: true })
|
|
25
26
|
if (!dryRun) mkdirSync(join(dstDir, 'dist'), { recursive: true })
|
|
26
27
|
|
|
27
28
|
// Drop legacy raw copies from previous installs (root index.tsx + dist/tui.tsx).
|
|
28
|
-
// The loader consumes only the bundle, so stale raws must not linger.
|
|
29
29
|
if (!dryRun) {
|
|
30
30
|
rmSync(join(dstDir, 'index.tsx'), { force: true })
|
|
31
31
|
rmSync(join(dstDir, 'dist', 'tui.tsx'), { force: true })
|
|
@@ -45,15 +45,45 @@ export function copyPluginFiles(srcDir, dstDir, { dryRun = false } = {}) {
|
|
|
45
45
|
// Copy package.json
|
|
46
46
|
const pkgSrc = join(srcDir, 'package.json')
|
|
47
47
|
if (existsSync(pkgSrc)) {
|
|
48
|
+
const packageJson = JSON.parse(readFileSync(pkgSrc, 'utf8'))
|
|
49
|
+
if (version === 'v2' && packageJson.exports?.['./tui-v2']) {
|
|
50
|
+
packageJson.exports['./tui'] = packageJson.exports['./tui-v2']
|
|
51
|
+
}
|
|
48
52
|
const pkgStatus = writeIfChanged(
|
|
49
53
|
join(dstDir, 'package.json'),
|
|
50
|
-
|
|
54
|
+
`${JSON.stringify(packageJson, null, 2)}\n`,
|
|
51
55
|
dryRun,
|
|
52
56
|
)
|
|
53
57
|
if (pkgStatus === 'created') result.created++
|
|
54
58
|
else result.skipped++
|
|
55
59
|
}
|
|
56
60
|
|
|
61
|
+
// Each host generation receives its own root loader and compiled bundle.
|
|
62
|
+
const tuiEntrySrc = join(srcDir, version === 'v2' ? 'tui-v2.ts' : 'tui.ts')
|
|
63
|
+
if (existsSync(tuiEntrySrc)) {
|
|
64
|
+
const entryStatus = writeIfChanged(
|
|
65
|
+
join(dstDir, 'tui.ts'),
|
|
66
|
+
readFileSync(tuiEntrySrc, 'utf8'),
|
|
67
|
+
dryRun,
|
|
68
|
+
)
|
|
69
|
+
if (entryStatus === 'created') result.created++
|
|
70
|
+
else result.skipped++
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
const v2ServerEntry = join(srcDir, 'index-v2.ts')
|
|
74
|
+
const v2ServerDestination = join(dstDir, 'index.ts')
|
|
75
|
+
if (version === 'v2' && existsSync(v2ServerEntry)) {
|
|
76
|
+
const entryStatus = writeIfChanged(
|
|
77
|
+
v2ServerDestination,
|
|
78
|
+
readFileSync(v2ServerEntry, 'utf8'),
|
|
79
|
+
dryRun,
|
|
80
|
+
)
|
|
81
|
+
if (entryStatus === 'created') result.created++
|
|
82
|
+
else result.skipped++
|
|
83
|
+
} else if (!dryRun) {
|
|
84
|
+
rmSync(v2ServerDestination, { force: true })
|
|
85
|
+
}
|
|
86
|
+
|
|
57
87
|
// Copy the lockfile so dependency installation is reproducible. A missing
|
|
58
88
|
// lockfile is intentionally not synthesized by the installer.
|
|
59
89
|
const lockSrc = join(srcDir, 'package-lock.json')
|
|
@@ -79,14 +109,18 @@ export function copyPluginFiles(srcDir, dstDir, { dryRun = false } = {}) {
|
|
|
79
109
|
* @param {boolean} [options.clean=false] - If true, remove existing before install
|
|
80
110
|
* @returns {{ created: number, skipped: number, errors: number }}
|
|
81
111
|
*/
|
|
82
|
-
export function installPlugin(
|
|
112
|
+
export function installPlugin(
|
|
113
|
+
srcDir,
|
|
114
|
+
dstDir,
|
|
115
|
+
{ dryRun = false, clean = false, version = 'v1' } = {},
|
|
116
|
+
) {
|
|
83
117
|
const result = { created: 0, skipped: 0, errors: 0 }
|
|
84
118
|
|
|
85
119
|
if (clean && existsSync(dstDir) && !dryRun) {
|
|
86
120
|
rmSync(dstDir, { recursive: true, force: true })
|
|
87
121
|
}
|
|
88
122
|
|
|
89
|
-
const copyResult = copyPluginFiles(srcDir, dstDir, { dryRun })
|
|
123
|
+
const copyResult = copyPluginFiles(srcDir, dstDir, { dryRun, version })
|
|
90
124
|
result.created += copyResult.created
|
|
91
125
|
result.skipped += copyResult.skipped
|
|
92
126
|
|
|
@@ -40,6 +40,7 @@ const MCP_SCRIPTS = {
|
|
|
40
40
|
'pantheon_vision.py': () => join(ROOT, 'src', 'mcp', 'pantheon_vision.py'),
|
|
41
41
|
'eval_store.py': () => join(ROOT, 'src', 'mcp', 'eval_store.py'),
|
|
42
42
|
'scrub-secrets.py': () => join(ROOT, 'scripts', 'scrub-secrets.py'),
|
|
43
|
+
'themis_heuristic_scan.py': () => join(ROOT, 'scripts', 'themis_heuristic_scan.py'),
|
|
43
44
|
}
|
|
44
45
|
|
|
45
46
|
/**
|
package/scripts/sync-tui.mjs
CHANGED
|
@@ -14,6 +14,7 @@ import { existsSync, mkdirSync, readdirSync, readFileSync, rmSync, writeFileSync
|
|
|
14
14
|
import { homedir } from 'node:os'
|
|
15
15
|
import { join } from 'node:path'
|
|
16
16
|
import { fileURLToPath, pathToFileURL } from 'node:url'
|
|
17
|
+
import { resolveOpenCodeVersion } from './install/opencode-version.mjs'
|
|
17
18
|
|
|
18
19
|
const __dirname = fileURLToPath(new URL('.', import.meta.url))
|
|
19
20
|
const ROOT = join(__dirname, '..')
|
|
@@ -63,7 +64,7 @@ function resolveConfigDir() {
|
|
|
63
64
|
* The raw TSX source is never copied — the loader consumes only the bundle.
|
|
64
65
|
* @returns {{ created: number, skipped: number }}
|
|
65
66
|
*/
|
|
66
|
-
function copyPluginFiles(srcDir, dstDir) {
|
|
67
|
+
function copyPluginFiles(srcDir, dstDir, version) {
|
|
67
68
|
const result = { created: 0, skipped: 0 }
|
|
68
69
|
|
|
69
70
|
mkdirSync(dstDir, { recursive: true })
|
|
@@ -87,11 +88,30 @@ function copyPluginFiles(srcDir, dstDir) {
|
|
|
87
88
|
// package.json
|
|
88
89
|
const pkgSrc = join(srcDir, 'package.json')
|
|
89
90
|
if (existsSync(pkgSrc)) {
|
|
90
|
-
const
|
|
91
|
+
const packageJson = JSON.parse(readFileSync(pkgSrc, 'utf8'))
|
|
92
|
+
if (version === 'v2' && packageJson.exports?.['./tui-v2']) {
|
|
93
|
+
packageJson.exports['./tui'] = packageJson.exports['./tui-v2']
|
|
94
|
+
}
|
|
95
|
+
const content = `${JSON.stringify(packageJson, null, 2)}\n`
|
|
91
96
|
if (writeIfChanged(join(dstDir, 'package.json'), content)) result.created++
|
|
92
97
|
else result.skipped++
|
|
93
98
|
}
|
|
94
99
|
|
|
100
|
+
const tuiEntry = join(srcDir, version === 'v2' ? 'tui-v2.ts' : 'tui.ts')
|
|
101
|
+
if (existsSync(tuiEntry)) {
|
|
102
|
+
if (writeIfChanged(join(dstDir, 'tui.ts'), readFileSync(tuiEntry, 'utf8'))) result.created++
|
|
103
|
+
else result.skipped++
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
const v2ServerEntry = join(srcDir, 'index-v2.ts')
|
|
107
|
+
const v2ServerDestination = join(dstDir, 'index.ts')
|
|
108
|
+
if (version === 'v2' && existsSync(v2ServerEntry)) {
|
|
109
|
+
if (writeIfChanged(v2ServerDestination, readFileSync(v2ServerEntry, 'utf8'))) result.created++
|
|
110
|
+
else result.skipped++
|
|
111
|
+
} else if (existsSync(v2ServerDestination)) {
|
|
112
|
+
rmSync(v2ServerDestination, { force: true })
|
|
113
|
+
}
|
|
114
|
+
|
|
95
115
|
// Keep the copied plugin installable with deterministic npm ci.
|
|
96
116
|
const lockSrc = join(srcDir, 'package-lock.json')
|
|
97
117
|
if (existsSync(lockSrc)) {
|
|
@@ -169,7 +189,8 @@ async function main() {
|
|
|
169
189
|
const sourceVersion = readVersion(join(tuiSrcDir, 'package.json'))
|
|
170
190
|
|
|
171
191
|
// Copy fresh files
|
|
172
|
-
const {
|
|
192
|
+
const version = resolveOpenCodeVersion('auto', { warn: (message) => console.warn(message) })
|
|
193
|
+
const { created } = copyPluginFiles(tuiSrcDir, tuiCopyDir, version)
|
|
173
194
|
|
|
174
195
|
// Lockfile installation is the only accepted dependency path. Strip
|
|
175
196
|
// global-context npm vars so a global postinstall can't trigger ECIGLOBAL.
|
package/skills-lock.json
CHANGED
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
"src/skills/memory-bank/SKILL.md": "4717cf18b43550c9f02cfab810968b97a5b2584f00a15516ecba643c80cdc110",
|
|
13
13
|
"src/skills/reflect/SKILL.md": "4c7608c2a55cb8a50ac90fc0e2446bdf25e7914b1748cb7731c311d13c29dfdd",
|
|
14
14
|
"src/skills/security-hardening/SKILL.md": "6d637e122421f7bc3b751f04854ad343a5a5d35249458bc8939233138fd3f20d",
|
|
15
|
-
"src/skills/session-goal/SKILL.md": "
|
|
15
|
+
"src/skills/session-goal/SKILL.md": "3a708d15a59a6bff2dd32ff7ead6548ecccc7be8d39437fee3133ea6254b6134",
|
|
16
16
|
"src/skills/simplify/SKILL.md": "aa739e9f75962a77d6574557d674ea01b5aea95e580b721d66c058753161b053",
|
|
17
17
|
"src/skills/spec-driven-development/SKILL.md": "e93b9103d6cd1848ab01328efde82c1daf564d1cabbdc2278254b346fcf55d02",
|
|
18
18
|
"src/skills/tdd-with-agents/SKILL.md": "9d20607ea34fc3e02c7e3ef5186b103d84196bd9a13aaadd55a44f41339125da",
|
package/src/agents/mnemosyne.md
CHANGED
|
@@ -12,17 +12,9 @@ mcp_tools:
|
|
|
12
12
|
- memory_recall
|
|
13
13
|
- memory_store
|
|
14
14
|
- memory_search
|
|
15
|
-
-
|
|
16
|
-
-
|
|
17
|
-
-
|
|
18
|
-
- memory_link
|
|
19
|
-
- memory_traverse
|
|
20
|
-
- memory_compress
|
|
21
|
-
- memory_consolidate
|
|
22
|
-
- memory_verify
|
|
23
|
-
- memory_sessions
|
|
24
|
-
- memory_expand
|
|
25
|
-
- memory_cleanup
|
|
15
|
+
- memory_forget
|
|
16
|
+
- memory_list
|
|
17
|
+
- memory_stats
|
|
26
18
|
pantheon-code-mode: [execute_code_script]
|
|
27
19
|
skills:
|
|
28
20
|
- artifact-management
|
|
@@ -64,6 +56,7 @@ If asked to edit code, refuse and redirect to the appropriate implementation age
|
|
|
64
56
|
- Close sprints (wipe .tmp/)
|
|
65
57
|
- Clean tmp without closing sprint
|
|
66
58
|
- List artifacts
|
|
59
|
+
- Use `memory_forget` only for an explicitly requested durable-memory deletion; do not delete automatically.
|
|
67
60
|
|
|
68
61
|
### 2. Artifact Management
|
|
69
62
|
- Create artifacts in .pantheon/memory-bank/.tmp/ (PLAN, IMPL, REVIEW, DISC)
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tui-v2.d.ts","names":[],"sources":["../src/index-v2.tsx"],"mappings":";;cAuFM;;EAEW,MAAA"}
|