Skip to content
Merged
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
32 changes: 28 additions & 4 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,9 @@ jobs:
os: [windows-latest, ubuntu-latest]
python-version: ["3.11", "3.13"]
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v6

- uses: actions/setup-python@v5
- uses: actions/setup-python@v6
with:
python-version: ${{ matrix.python-version }}
cache: pip
Expand All @@ -39,9 +39,9 @@ jobs:
runs-on: ubuntu-latest
timeout-minutes: 10
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v6

- uses: actions/setup-python@v5
- uses: actions/setup-python@v6
with:
python-version: "3.13"
cache: pip
Expand All @@ -59,3 +59,27 @@ jobs:

- name: Build package
run: python -m build

- name: Verify release versions
run: python scripts/check_release_versions.py

npm-launcher:
name: npm wrapper-only launcher
runs-on: ubuntu-latest
timeout-minutes: 10
steps:
- uses: actions/checkout@v6

- uses: actions/setup-node@v6
with:
node-version: "24"
cache: npm
cache-dependency-path: js/package-lock.json

- name: Install, test, and build thin launcher
working-directory: js
run: |
npm ci
npm test
npm run build
npm pack --dry-run
56 changes: 52 additions & 4 deletions .github/workflows/pypi-publish.yml
Original file line number Diff line number Diff line change
@@ -1,22 +1,27 @@
name: Publish to PyPI
name: Publish packages

on:
workflow_dispatch:
inputs:
version:
description: "Release version or tag (for example 2.6.0 or v2.6.0)"
required: true
type: string
release:
types: [published]

jobs:
publish:
name: Build and publish package
name: Build and publish PyPI core
runs-on: ubuntu-latest
environment: pypi
permissions:
contents: read
id-token: write
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v6

- uses: actions/setup-python@v5
- uses: actions/setup-python@v6
with:
python-version: "3.13"
cache: pip
Expand All @@ -29,8 +34,51 @@ jobs:
- name: Build distributions
run: python -m build

- name: Verify synchronized release version
env:
RELEASE_VERSION: ${{ github.event.release.tag_name || inputs.version }}
run: python scripts/check_release_versions.py --tag "$RELEASE_VERSION"

- name: Check distributions
run: python -m twine check dist/*

- name: Publish to PyPI
uses: pypa/gh-action-pypi-publish@release/v1

publish-npm:
name: Publish npm launcher after PyPI
needs: publish
runs-on: ubuntu-latest
environment: npm
permissions:
contents: read
id-token: write
steps:
- uses: actions/checkout@v6

- uses: actions/setup-python@v6
with:
python-version: "3.13"

- uses: actions/setup-node@v6
with:
node-version: "24"
registry-url: "https://registry.npmjs.org"
package-manager-cache: false

- name: Verify synchronized release version
env:
RELEASE_VERSION: ${{ github.event.release.tag_name || inputs.version }}
run: python scripts/check_release_versions.py --tag "$RELEASE_VERSION"

- name: Wait for the matching PyPI core
env:
RELEASE_VERSION: ${{ github.event.release.tag_name || inputs.version }}
run: python scripts/wait_for_pypi.py --version "$RELEASE_VERSION"

- name: Test and publish wrapper-only npm package
working-directory: js
run: |
npm ci
npm test
npm publish
16 changes: 16 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,21 @@
# Changelog

## v2.6.0

### Fixed

- Preserve quoted arguments on Windows by launching native executables without a second `cmd.exe` parsing pass.
- Add `--cwd` and `SAGE_WORKSPACE_CWD` so Electron and other desktop hosts can supply the real project directory.
- Make foreground telemetry sync non-blocking; proof snapshots remain handled by the detached sender.
- Keep the npm launcher and PyPI core compatible by upgrading an older Python core before delegation.
- Synchronize Python, npm, lockfile, exported, and MCP version metadata.

### Packaging

- Keep npm install passive and publish only the thin launcher/bridge files.
- Publish PyPI first and npm second from one GitHub release workflow using trusted publishing.
- Add release version checks, npm launcher CI, package dry-runs, and a PyPI-availability gate before npm publish.

## v2.4.3

### Fixed
Expand Down
1 change: 1 addition & 0 deletions MANIFEST.in
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,6 @@
prune electron
prune src/sage/gui
prune src/sage/dashboard
prune src/sage/tui
exclude src/sage/gui_server.py
exclude tests/test_dashboard_render.py
5 changes: 4 additions & 1 deletion NPM_SECURITY_REVIEW.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

The npm package `psycgod-sage` is intended to be a safe launcher for the canonical PyPI package `psycgod-sage`.

As of npm package version `1.0.19`:
As of npm package version `2.6.0`:

- `npm install -g psycgod-sage` is passive.
- There is no `preinstall`, `install`, or `postinstall` lifecycle script.
Expand All @@ -15,6 +15,9 @@ As of npm package version `1.0.19`:
- Agent hook installation is best-effort and non-blocking for normal command execution.
- Hook denials do not print the blocked command, to avoid leaking secrets from command lines into AI context or logs.
- Hook installation merges with existing hook settings instead of replacing a user's existing hooks.
- The package allowlist contains only the launcher, the Python bridge, and their declarations/source maps.
- The launcher verifies that the installed PyPI core is at least the compatibility version declared by npm.
- Desktop hosts can pass the workspace through `SAGE_WORKSPACE_CWD` without changing global process state.

## Why this changed

Expand Down
22 changes: 12 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -70,19 +70,19 @@ SAGE does not auto-enable MCP. MCP is optional and manual for users who want it.

## Live Proof

Latest pulled stats as of 2026-07-22:
Latest pulled stats as of 2026-08-01:

| Metric | Value |
|---|---:|
| SAGE telemetry command events | 23,081 |
| Tokens processed | 750.0M |
| Tokens saved | 736.1M |
| Compression rate | 98.14% |
| Estimated savings | $15,273.07 |
| Command success rate | 89.7% |
| PyPI downloads, last 7 days | 885 |
| npm downloads, last 7 days | 1,268 |
| GitHub clones, last 14 days | 1,635 |
| SAGE telemetry command events | 27,892 |
| Tokens processed | 799.5M |
| Tokens saved | 783.7M |
| Compression rate | 98.02% |
| Estimated savings | $16,261.90 |
| Command success rate | 88.3% |
| PyPI downloads, last 7 days | 632 |
| npm downloads, last 7 days | 362 |
| GitHub clones, last 14 days | 574 |

Live dashboard: [sage.api.marketingstudios.in/dashboard](https://sage.api.marketingstudios.in/dashboard)
Install page: [sage.api.marketingstudios.in/install](https://sage.api.marketingstudios.in/install)
Expand Down Expand Up @@ -119,6 +119,7 @@ sage install # Activate this machine and AI-agent instruct
sage doctor --activation # Verify activation
npx -y psycgod-sage doctor --activation
sage run -- <command> # Wrap any command
sage run --cwd /project -- <command> # Explicit workspace for desktop/Electron hosts
sage pytest # Shortcut for: sage run -- pytest
sage npm test # Shortcut for: sage run -- npm test
sage git status # Shortcut for: sage run -- git status
Expand Down Expand Up @@ -149,6 +150,7 @@ SAGE is designed to keep prompts, source code, credentials, raw command output,
|---|---|
| Already-open AI-agent sessions may not reload new instructions | Restart Claude/Codex/Cursor/Windsurf/OpenCode after `sage install` |
| Locked-down host apps can disable shell tools | SAGE cannot enable tools the host application has blocked |
| A desktop/Electron host starts its shell in the wrong folder | Pass `sage run --cwd <project> -- <command>` or set `SAGE_WORKSPACE_CWD` |
| npm/PyPI installs cannot safely auto-run activation | Run `sage install` once after package install |
| MCP can disconnect in some stdio agent sessions | Use normal `sage run -- <command>` by default; enable MCP manually only if needed |
| Package installs are passive by design | Real activation starts with `sage install` |
Expand Down
12 changes: 12 additions & 0 deletions cloudflare/sage-api/schema/oauth_sessions.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
-- GitHub OAuth session store for server-side callback flow.
CREATE TABLE IF NOT EXISTS oauth_sessions (
session_id TEXT PRIMARY KEY,
state TEXT NOT NULL DEFAULT 'pending',
status TEXT NOT NULL DEFAULT 'pending',
payload_json TEXT NOT NULL DEFAULT '{}',
created_at TEXT NOT NULL,
expires_at TEXT NOT NULL
);

CREATE INDEX IF NOT EXISTS idx_oauth_sessions_state ON oauth_sessions(state);
CREATE INDEX IF NOT EXISTS idx_oauth_sessions_expires ON oauth_sessions(expires_at);
12 changes: 12 additions & 0 deletions cloudflare/sage-api/schema/schema.sql
Original file line number Diff line number Diff line change
Expand Up @@ -74,3 +74,15 @@ CREATE INDEX IF NOT EXISTS idx_telemetry_workspace ON telemetry_events(workspace
CREATE INDEX IF NOT EXISTS idx_telemetry_kind ON telemetry_events(command_kind, received_at);
CREATE INDEX IF NOT EXISTS idx_aggregate_daily_key ON aggregate_daily(key_id, day);

CREATE TABLE IF NOT EXISTS oauth_sessions (
session_id TEXT PRIMARY KEY,
state TEXT NOT NULL DEFAULT 'pending',
status TEXT NOT NULL DEFAULT 'pending',
payload_json TEXT NOT NULL DEFAULT '{}',
created_at TEXT NOT NULL,
expires_at TEXT NOT NULL
);

CREATE INDEX IF NOT EXISTS idx_oauth_sessions_state ON oauth_sessions(state);
CREATE INDEX IF NOT EXISTS idx_oauth_sessions_expires ON oauth_sessions(expires_at);

Loading