Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions INSTALL.md
Original file line number Diff line number Diff line change
Expand Up @@ -215,6 +215,10 @@ Use `simplicio deliver certify` before declaring done.
### OpenAI Codex / ChatGPT

Same workflow — Simplicio commands work from any terminal-based AI agent.
The shell and PowerShell installers detect the `codex` CLI and install or
update the Simplicio Codex plugin automatically. When Codex is absent, the
installer leaves the plugin step untouched; set `SIMPLICIO_SKIP_CODEX_PLUGIN=1`
only to opt out explicitly.

## Fontes Python no Runtime

Expand Down
5 changes: 5 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,11 @@ codex plugin marketplace add wesleysimplicio/simplicio --ref master
codex plugin add simplicio@simplicio-codex
```

The shell and PowerShell installers also detect the `codex` CLI and install
or update this plugin automatically. If Codex is not present, that step is
skipped. Set `SIMPLICIO_SKIP_CODEX_PLUGIN=1` only when you explicitly want
to disable the automatic plugin installation.

The official installers download one canonical asset from the latest
Runtime release, verify its SHA256 checksum and Ed25519 signature, validate the
Runtime release contract, and register MCP hosts to launch the installed binary
Expand Down
36 changes: 36 additions & 0 deletions install.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
# SIMPLICIO_ALLOW_UNVERIFIED - "1" to proceed even if no checksum is
# published for this target (default: refuse)
# SIMPLICIO_BUNDLE_DIR - Runtime report directory (default: ~/.simplicio)
# SIMPLICIO_SKIP_CODEX_PLUGIN - "1" to skip automatic Codex plugin installation
#
# Asset naming follows distribution/targets.json (the canonical target
# triplet table for the whole ecosystem) — target "windows-x64", asset
Expand Down Expand Up @@ -44,6 +45,9 @@ $PinnedPublicKey = ([string]$Ed25519PublicKey).Trim()
$script:Ed25519VerifyError = ""
$SimplicioMcpUrl = if ($env:SIMPLICIO_MCP_URL) { $env:SIMPLICIO_MCP_URL } else { "http://127.0.0.1:8787/mcp" }

$CodexPluginMarketplace = if ($env:SIMPLICIO_CODEX_MARKETPLACE) { $env:SIMPLICIO_CODEX_MARKETPLACE } else { "simplicio-codex" }
$CodexPluginSource = if ($env:SIMPLICIO_CODEX_PLUGIN_SOURCE) { $env:SIMPLICIO_CODEX_PLUGIN_SOURCE } else { "wesleysimplicio/simplicio" }
$CodexPluginRef = if ($env:SIMPLICIO_CODEX_PLUGIN_REF) { $env:SIMPLICIO_CODEX_PLUGIN_REF } else { "master" }
if ($env:SIMPLICIO_BIN_DIR) {
$InstallDir = $env:SIMPLICIO_BIN_DIR
} else {
Expand Down Expand Up @@ -197,6 +201,37 @@ function Test-McpToolSurface([string]$BinaryPath) {
}
}

function Install-CodexPlugin {
if ($env:SIMPLICIO_SKIP_CODEX_PLUGIN -eq "1") { return }
$codex = Get-Command codex -ErrorAction SilentlyContinue
if ($null -eq $codex) {
Write-Host " - Codex not detected; Simplicio plugin was not installed"
return
}

Write-Host "==> Codex detected; installing Simplicio plugin..."
& $codex.Source plugin marketplace add $CodexPluginSource --ref $CodexPluginRef --json | Out-Null
if ($LASTEXITCODE -ne 0) {
Write-Warning "Could not update the Codex marketplace; trying the configured marketplace"
}

& $codex.Source plugin add "simplicio@$CodexPluginMarketplace" --json | Out-Null
if ($LASTEXITCODE -eq 0) {
Write-Host " ✓ Simplicio plugin installed in Codex"
return
}

if ($CodexPluginMarketplace -ne "simplicio") {
& $codex.Source plugin add "simplicio@simplicio" --json | Out-Null
if ($LASTEXITCODE -eq 0) {
Write-Host " ✓ Simplicio plugin installed in Codex (existing marketplace)"
return
}
}

Write-Warning "Codex detected, but the Simplicio plugin could not be installed automatically"
Write-Warning "Install manually: codex plugin marketplace add $CodexPluginSource --ref $CodexPluginRef; codex plugin add simplicio@$CodexPluginMarketplace"
}
# ─── -Doctor: idempotent, read-only health check ───────────────────────────
if ($Doctor) {
Write-Host "==> simplicio doctor"
Expand Down Expand Up @@ -462,6 +497,7 @@ if (Test-McpToolSurface $DestPath) {
Write-Error "Runtime installed, but automatic MCP/hooks registration failed: $DestPath mcp register --binary $DestPath --json"
exit 1
}
Install-CodexPlugin
Report-LoginState
Write-Host " ✓ Direct MCP: $DestPath serve --mcp --stdio; SIMPLICIO_MCP_URL=$SimplicioMcpUrl"

Expand Down
35 changes: 35 additions & 0 deletions install.sh
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
# SIMPLICIO_ALLOW_UNVERIFIED - "1" to proceed even if no checksum is
# published for this target (default: refuse)
# SIMPLICIO_BUNDLE_DIR - bundle report directory (default: ~/.simplicio)
# SIMPLICIO_SKIP_CODEX_PLUGIN - "1" to skip automatic Codex plugin installation
#
# Asset naming follows distribution/targets.json (the canonical target
# triplet table for the whole ecosystem): id "macos-arm64" -> asset
Expand Down Expand Up @@ -224,6 +225,39 @@ verify_mcp_tools() {
SIMPLICIO_MCP_URL="$SIMPLICIO_MCP_URL" "$binary_path" mcp register --binary "$binary_path" --json >/dev/null 2>&1
}

CODEX_PLUGIN_MARKETPLACE="${SIMPLICIO_CODEX_MARKETPLACE:-simplicio-codex}"
CODEX_PLUGIN_SOURCE="${SIMPLICIO_CODEX_PLUGIN_SOURCE:-wesleysimplicio/simplicio}"
CODEX_PLUGIN_REF="${SIMPLICIO_CODEX_PLUGIN_REF:-master}"

install_codex_plugin() {
if [ "${SIMPLICIO_SKIP_CODEX_PLUGIN:-}" = "1" ]; then
return 0
fi
if ! command -v codex >/dev/null 2>&1; then
info "Codex não detectado; plugin Simplicio não será instalado"
return 0
fi

info "Codex detectado; instalando o plugin Simplicio..."
if ! codex plugin marketplace add "$CODEX_PLUGIN_SOURCE" --ref "$CODEX_PLUGIN_REF" --json >/dev/null 2>&1; then
warn "não foi possível atualizar o marketplace Codex; tentando o marketplace já configurado"
fi

if codex plugin add "simplicio@$CODEX_PLUGIN_MARKETPLACE" --json >/dev/null 2>&1; then
ok "plugin Simplicio instalado no Codex"
return 0
fi

if [ "$CODEX_PLUGIN_MARKETPLACE" != "simplicio" ] && codex plugin add "simplicio@simplicio" --json >/dev/null 2>&1; then
ok "plugin Simplicio instalado no Codex (marketplace já configurado)"
return 0
fi

warn "Codex detectado, mas o plugin Simplicio não pôde ser instalado automaticamente"
warn "instale manualmente: codex plugin marketplace add $CODEX_PLUGIN_SOURCE --ref $CODEX_PLUGIN_REF && codex plugin add simplicio@$CODEX_PLUGIN_MARKETPLACE"
return 0
}

# ─── --doctor: idempotent, read-only health check ──────────────────────────
run_doctor() {
info "simplicio doctor"
Expand Down Expand Up @@ -531,6 +565,7 @@ if verify_mcp_tools "$DEST_PATH"; then
else
err "o Runtime foi instalado, mas o registro automático de MCP/hooks falhou: $DEST_PATH mcp register --binary $DEST_PATH --json"
fi
install_codex_plugin
report_login_state
ok "MCP direto: $DEST_PATH serve --mcp --stdio; SIMPLICIO_MCP_URL=${SIMPLICIO_MCP_URL}"

Expand Down
2 changes: 1 addition & 1 deletion plugins/simplicio/bin/simplicio-mcp-bootstrap.js
Original file line number Diff line number Diff line change
Expand Up @@ -250,7 +250,7 @@ function runOfficialInstaller(installerPath, home, logPath) {
USERPROFILE: isolatedHome,
SIMPLICIO_BIN_DIR: managedBinDir,
SIMPLICIO_BUNDLE_DIR: path.join(isolatedHome, ".simplicio"),
SIMPLICIO_INSTALL_CODEX: "0",
SIMPLICIO_SKIP_CODEX_PLUGIN: "1",
SIMPLICIO_VERSION: POLICY.runtimeVersion
};
delete env.SIMPLICIO_ALLOW_UNVERIFIED;
Expand Down
5 changes: 5 additions & 0 deletions plugins/simplicio/tests/bootstrap.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,11 @@ test("installer policy is pinned to immutable content", () => {
assert.match(bootstrap.POLICY.installers.posix.sha256, /^[0-9a-f]{64}$/);
assert.match(bootstrap.POLICY.installers.win32.sha256, /^[0-9a-f]{64}$/);
});
test("official installer bootstrap skips recursive Codex plugin installation", () => {
const source = fs.readFileSync(bootstrapPath, "utf8");
assert.match(source, /SIMPLICIO_SKIP_CODEX_PLUGIN: "1"/);
assert.doesNotMatch(source, /SIMPLICIO_INSTALL_CODEX/);
});

test("installer download follows redirects and fails closed on HTTP errors", async () => {
await assert.rejects(
Expand Down
4 changes: 2 additions & 2 deletions tests/install_error_registry.json
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@
"root_cause": "The public installers required an opt-in environment variable and downloaded a second hook artifact.",
"guard": "Every installer delegates automatic host and Runtime-owned hook registration to `simplicio mcp register --binary <installed> --json`; no Codex opt-in remains.",
"regression_tests": [
"tests/test_codex_integration_cli.py::test_installers_are_opt_in_and_do_not_use_mutable_master_hook_ref"
"tests/test_codex_integration_cli.py::test_installers_auto_install_codex_plugin_when_cli_is_present"
],
"fixed_commit": "7abc0f0428d65718cda709b57c51bcabb28b92ae"
},
Expand Down Expand Up @@ -315,7 +315,7 @@
"root_cause": "Host registration was split across installer-specific paths instead of the installed Runtime.",
"guard": "SH, PS1, and PyPI all invoke the installed Runtime registrar and fail clearly when its JSON status is not passed.",
"regression_tests": [
"tests/test_codex_install_contract.py::test_plain_install_registers_all_detected_hosts_without_codex_opt_in",
"tests/test_codex_install_contract.py::test_plain_install_registers_hosts_and_installs_codex_plugin_when_available",
"tests/unit/test_pypi_installer.py::test_install_registers_detected_hosts_with_installed_binary"
],
"fixed_commit": "7abc0f0428d65718cda709b57c51bcabb28b92ae"
Expand Down
14 changes: 9 additions & 5 deletions tests/test_codex_install_contract.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,18 +38,22 @@ def test_installers_configure_direct_stdio_and_hooks():
assert "--binary" in text
assert "--json" in text

def test_plain_install_registers_all_detected_hosts_without_codex_opt_in():
def test_plain_install_registers_hosts_and_installs_codex_plugin_when_available():
shell = (ROOT / "install.sh").read_text(encoding="utf-8")
powershell = (ROOT / "install.ps1").read_text(encoding="utf-8")

assert "SIMPLICIO_INSTALL_CODEX" not in shell
assert "SIMPLICIO_SKIP_CODEX_PLUGIN" in shell
assert "SIMPLICIO_CODEX_HOOK_REF" not in shell
assert "if require_active_login; then" not in shell
assert "command -v codex" in shell
assert 'plugin marketplace add "$CODEX_PLUGIN_SOURCE"' in shell
assert 'plugin add "simplicio@$CODEX_PLUGIN_MARKETPLACE"' in shell
assert 'mcp register --binary "$binary_path" --json' in shell

assert "SIMPLICIO_INSTALL_CODEX" not in powershell
assert "SIMPLICIO_SKIP_CODEX_PLUGIN" in powershell
assert "SIMPLICIO_CODEX_HOOK_REF" not in powershell
assert "if (Require-ActiveLogin)" not in powershell
assert "Get-Command codex" in powershell
assert "plugin marketplace add $CodexPluginSource" in powershell
assert 'plugin add "simplicio@$CodexPluginMarketplace"' in powershell
assert "mcp register --binary $BinaryPath --json" in powershell


Expand Down
12 changes: 9 additions & 3 deletions tests/test_codex_integration_cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,11 +50,17 @@ def test_windows_binary_path_is_toml_safe_and_uses_forward_slashes():
assert tomllib.loads(config)["mcp_servers"]["simplicio"]["command"] == expected


def test_installers_are_opt_in_and_do_not_use_mutable_master_hook_ref():
def test_installers_auto_install_codex_plugin_when_cli_is_present():
shell = (ROOT / "install.sh").read_text(encoding="utf-8")
powershell = (ROOT / "install.ps1").read_text(encoding="utf-8")
assert "SIMPLICIO_INSTALL_CODEX" not in shell
assert "SIMPLICIO_INSTALL_CODEX" not in powershell
assert "SIMPLICIO_SKIP_CODEX_PLUGIN" in shell
assert "SIMPLICIO_SKIP_CODEX_PLUGIN" in powershell
assert "command -v codex" in shell
assert "Get-Command codex" in powershell
assert 'plugin marketplace add "$CODEX_PLUGIN_SOURCE"' in shell
assert 'plugin add "simplicio@$CODEX_PLUGIN_MARKETPLACE"' in shell
assert "plugin marketplace add $CodexPluginSource" in powershell
assert 'plugin add "simplicio@$CodexPluginMarketplace"' in powershell
assert "SIMPLICIO_CODEX_HOOK_REF" not in shell
assert "SIMPLICIO_CODEX_HOOK_REF" not in powershell
assert 'mcp register --binary "$binary_path" --json' in shell
Expand Down