altimate-code 0.0.1 → 0.4.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 ADDED
@@ -0,0 +1,336 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project will be documented in this file.
4
+
5
+ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
6
+ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
+
8
+ ## [0.4.9] - 2026-03-18
9
+
10
+ ### Added
11
+
12
+ - Script to build and run compiled binary locally (#262)
13
+
14
+ ### Fixed
15
+
16
+ - Snowflake auth — support all auth methods (`password`, `keypair`, `externalbrowser`, `oauth`), fix field name mismatches (#268)
17
+ - dbt tool regression — schema format mismatch, silent failures, wrong results (#263)
18
+ - `altimate-dbt compile`, `execute`, and children commands fail with runtime errors (#255)
19
+ - `Cannot find module @altimateai/altimate-core` on `npm install` (#259)
20
+ - Dispatcher tests fail in CI due to shared module state (#257)
21
+
22
+ ### Changed
23
+
24
+ - CI: parallel per-target builds — 12 jobs, ~5 min wall clock instead of ~20 min (#254)
25
+ - CI: faster release — build parallel with test, lower compression, tighter timeouts (#251)
26
+ - Docker E2E tests skip in CI unless explicitly opted in (#253)
27
+
28
+ ## [0.4.1] - 2026-03-16
29
+ ## [0.4.2] - 2026-03-18
30
+
31
+ ### Breaking Changes
32
+
33
+ - **Python engine eliminated** — all 73 tool methods now run natively in TypeScript. No Python, pip, venv, or `altimate-engine` installation required. Fixes #210.
34
+
35
+ ### Added
36
+
37
+ - `@altimateai/drivers` shared workspace package with 10 database drivers (Snowflake, BigQuery, PostgreSQL, Databricks, Redshift, MySQL, SQL Server, Oracle, DuckDB, SQLite)
38
+ - Direct `@altimateai/altimate-core` napi-rs bindings — SQL analysis calls go straight to Rust (no Python intermediary)
39
+ - dbt-first SQL execution — automatically uses `profiles.yml` connection when in a dbt project
40
+ - Warehouse telemetry (5 event types: connect, query, introspection, discovery, census)
41
+ - 340+ new tests including E2E tests against live Snowflake, BigQuery, and Databricks accounts
42
+ - Encrypted key-pair auth support for Snowflake (PKCS8 PEM with passphrase)
43
+ - Comprehensive driver documentation at `docs/docs/drivers.md`
44
+
45
+ ### Fixed
46
+
47
+ - Python bridge connection failures for UV, conda, and non-standard venv setups (#210)
48
+ - SQL injection in finops/schema queries (parameterized queries + escape utility)
49
+ - Credential store no longer saves plaintext passwords
50
+ - SSH tunnel cleanup on SIGINT/SIGTERM
51
+ - Race condition in connection registry for concurrent access
52
+ - Databricks DATE_SUB syntax
53
+ - Redshift describeTable column name
54
+ - SQL Server describeTable includes views
55
+ - Dispatcher telemetry wrapped in try/catch
56
+ - Flaky test timeouts
57
+
58
+ ### Removed
59
+
60
+ - `packages/altimate-engine/` — entire Python package (~17,000 lines)
61
+ - `packages/opencode/src/altimate/bridge/` — JSON-RPC bridge
62
+ - `.github/workflows/publish-engine.yml` — PyPI publish workflow
63
+
64
+ ### Added
65
+
66
+ - Local-first tracing system replacing Langfuse (#183)
67
+
68
+ ### Fixed
69
+
70
+ - Engine not found when user's project has `.venv` in cwd — managed venv now takes priority (#199)
71
+ - Missing `[warehouses]` pip extra causing FinOps tools to fail with "snowflake-connector-python not installed" (#199)
72
+ - Engine install trusting stale manifest when venv/Python binary was deleted (#199)
73
+ - Extras changes not detected on upgrade — manifest now tracks installed extras (#199)
74
+ - Windows path handling for dev/cwd venv resolution (#199)
75
+ - Concurrent bridge startup race condition — added `pendingStart` mutex (#199)
76
+ - Unhandled spawn `error` event crashing host process on invalid Python path (#199)
77
+ - Bridge hung permanently after ping failure — child process now cleaned up (#199)
78
+ - `restartCount` incorrectly incremented on signal kills, prematurely disabling bridge (#199)
79
+ - TUI prompt corruption from engine bootstrap messages writing to stderr (#180)
80
+ - Tracing exporter timeout leaking timers (#191)
81
+ - Feedback submission failing when repo labels don't exist (#188)
82
+ - Pre-release security and resource cleanup fixes for tracing (#197)
83
+
84
+ ## [0.4.0] - 2026-03-15
85
+
86
+ ### Added
87
+
88
+ - Data-viz skill for data storytelling and visualizations (#170)
89
+ - AI Teammate training system with learn-by-example patterns (#148)
90
+
91
+ ### Fixed
92
+
93
+ - Sidebar shows "OpenCode" instead of "Altimate Code" after upstream merge (#168)
94
+ - Prevent upstream tags from polluting origin (#165)
95
+ - Show welcome box on first CLI run, not during postinstall (#163)
96
+
97
+ ### Changed
98
+
99
+ - Engine version bumped to 0.4.0
100
+
101
+ ## [0.3.1] - 2026-03-15
102
+
103
+ ### Fixed
104
+
105
+ - Database migration crash when upgrading from v0.2.x — backfill NULL migration names for Drizzle beta.16 compatibility (#161)
106
+ - Install banner not visible during `npm install` — moved output from stdout to stderr (#161)
107
+ - Verbose changelog dump removed from CLI startup (#161)
108
+ - `altimate upgrade` detection broken — `method()` and `latest()` referenced upstream `opencode-ai` package names instead of `@altimateai/altimate-code` (#161)
109
+ - Brew formula detection and upgrade referencing `opencode` instead of `altimate-code` (#161)
110
+ - Homebrew tap updated to v0.3.0 (was stuck at 0.1.4 due to expired `HOMEBREW_TAP_TOKEN`) (#161)
111
+ - `.opencode/memory/` references in docs updated to `.altimate-code/memory/` (#161)
112
+ - Stale `@opencode-ai/plugin` reference in CONTRIBUTING.md (#161)
113
+
114
+ ### Changed
115
+
116
+ - CI now uses path-based change detection to skip unaffected jobs (saves ~100s on non-TS changes) (#161)
117
+ - Release workflow gated on test job passing (#157)
118
+ - Upstream merge restricted to published GitHub releases only (#150)
119
+
120
+ ## [0.3.0] - 2026-03-15
121
+
122
+ ### Added
123
+
124
+ - AI-powered prompt enhancement (#144)
125
+ - Altimate Memory — persistent cross-session memory with TTL, namespaces, citations, and audit logging (#136)
126
+ - Upstream merge with OpenCode v1.2.26 (#142)
127
+
128
+ ### Fixed
129
+
130
+ - Sentry review findings from PR #144 (#147)
131
+ - OAuth token refresh retry and error handling for idle timeout (#133)
132
+ - Welcome banner on first CLI run after install/upgrade (#132)
133
+ - `@altimateai/altimate-code` npm package name restored after upstream rebase
134
+ - Replace `mock.module()` with `spyOn()` to fix 149 test failures (#153)
135
+
136
+ ### Changed
137
+
138
+ - Rebrand user-facing references to Altimate Code (#134)
139
+ - Bump `@modelcontextprotocol/sdk` dependency (#139)
140
+ - Engine version bumped to 0.3.0
141
+
142
+ ## [0.2.5] - 2026-03-13
143
+
144
+ ### Added
145
+
146
+ - `/feedback` command and `feedback_submit` tool for in-app user feedback (#89)
147
+ - Datamate manager — dynamic MCP server management (#99)
148
+ - Non-interactive mode for `mcp add` command with input validation
149
+ - `mcp remove` command
150
+ - Upstream merge with OpenCode v1.2.20
151
+
152
+ ### Fixed
153
+
154
+ - TUI crash after upstream merge (#98)
155
+ - `GitlabAuthPlugin` type incompatibility in plugin loader (#92)
156
+ - All test failures from fork restructure (#91)
157
+ - CI/CD workflow paths updated from `altimate-code` to `opencode`
158
+ - Fallback to global config when not in a git repo
159
+ - PR standards workflow `TEAM_MEMBERS` ref corrected from `dev` to `main` (#101)
160
+
161
+ ### Changed
162
+
163
+ - Removed self-hosted runners from public repo CI (#110)
164
+ - Migrated CI/release to ARC runners (#93, #94)
165
+ - Reverted Windows tests to `windows-latest` (#95)
166
+ - Engine version bumped to 0.2.5
167
+
168
+ ## [0.2.4] - 2026-03-04
169
+
170
+ ### Added
171
+
172
+ - E2E tests for npm install pipeline: postinstall script, bin wrapper, and publish output (#50)
173
+
174
+ ## [0.2.3] - 2026-03-04
175
+
176
+ ### Added
177
+
178
+ - Postinstall welcome banner and changelog display after upgrade (#48)
179
+
180
+ ### Fixed
181
+
182
+ - Security: validate well-known auth command type before execution, add confirmation prompt (#45)
183
+ - CI/CD: SHA-pin all GitHub Actions, per-job least-privilege permissions (#45)
184
+ - MCP: fix copy-paste log messages, log init errors, prefix floating promises (#45)
185
+ - Session compaction: clean up compactionAttempts on abort to prevent memory leak (#45)
186
+ - Telemetry: retry failed flush events once with buffer-size cap (#45, #46)
187
+ - Telemetry: flush events before process exit (#46)
188
+ - TUI: resolve worker startup crash from circular dependency (#47)
189
+ - CLI: define ALTIMATE_CLI build-time constants for correct version reporting (#41)
190
+ - Address 4 issues found in post-v0.2.2 commits (#49)
191
+ - Address remaining code review issues from PR #39 (#43)
192
+
193
+ ### Changed
194
+
195
+ - CI/CD: optimize pipeline with caching and parallel builds (#42)
196
+
197
+ ### Docs
198
+
199
+ - Add security FAQ (#44)
200
+
201
+ ## [0.2.2] - 2026-03-05
202
+
203
+ ### Fixed
204
+
205
+ - Telemetry init: `Config.get()` failure outside Instance context no longer silently disables telemetry
206
+ - Telemetry init: called early in CLI middleware and worker thread so MCP/engine/auth events are captured
207
+ - Telemetry init: promise deduplication prevents concurrent init race conditions
208
+ - Telemetry: pre-init events are now buffered and flushed (previously silently dropped)
209
+ - Telemetry: user email is SHA-256 hashed before sending (privacy)
210
+ - Telemetry: error message truncation standardized to 500 chars across all event types
211
+ - Telemetry: `ALTIMATE_TELEMETRY_DISABLED` env var now actually checked in init
212
+ - Telemetry: MCP disconnect reports correct transport type instead of hardcoded `stdio`
213
+ - Telemetry: `agent_outcome` now correctly reports `"error"` outcome for failed sessions
214
+
215
+ ### Changed
216
+
217
+ - Auth telemetry events use session context when available instead of hardcoded `"cli"`
218
+
219
+ ## [0.2.1] - 2026-03-05
220
+
221
+ ### Added
222
+
223
+ - Comprehensive telemetry instrumentation: 25 event types across auth, MCP servers, Python engine, provider errors, permissions, upgrades, context utilization, agent outcomes, workflow sequencing, and environment census
224
+ - Telemetry docs page with event table, privacy policy, opt-out instructions, and contributor guide
225
+ - AppInsights endpoint added to network firewall documentation
226
+ - `categorizeToolName()` helper for tool classification (sql, schema, dbt, finops, warehouse, lineage, file, mcp)
227
+ - `bucketCount()` helper for privacy-safe count bucketing
228
+
229
+ ### Fixed
230
+
231
+ - Command loading made resilient to MCP/Skill initialization failures
232
+
233
+ ### Changed
234
+
235
+ - CLI binary renamed from `altimate-code` to `altimate`
236
+
237
+ ## [0.2.0] - 2026-03-04
238
+
239
+ ### Added
240
+
241
+ - Context management: auto-compaction with overflow recovery, observation masking, and loop protection
242
+ - Context management: data-engineering-aware compaction template preserving warehouse, schema, dbt, and lineage context
243
+ - Context management: content-aware token estimation (code, JSON, SQL, text heuristics)
244
+ - Context management: observation masking replaces pruned tool outputs with fingerprinted summaries
245
+ - Context management: provider overflow detection for Azure OpenAI patterns
246
+ - CLI observability: telemetry module with session, generation, tool call, and error tracking
247
+ - `/discover` command for data stack setup with project_scan tool
248
+ - User documentation for context management configuration
249
+
250
+ ### Fixed
251
+
252
+ - ContextOverflowError now triggers automatic compaction instead of a dead-end error
253
+ - `isOverflow()` correctly reserves headroom for models with separate input/output limits
254
+ - `NamedError.isInstance()` no longer crashes on null input
255
+ - Text part duration tracking now preserves original start timestamp
256
+ - Compaction loop protection: max 3 consecutive attempts per turn, counter resets between turns
257
+ - Negative usable context guard for models where headroom exceeds base capacity
258
+
259
+ ### Changed
260
+
261
+ - Removed cost estimation and complexity scoring bindings
262
+ - Docs: redesigned homepage with hero, feature cards, and pill layouts
263
+ - Docs: reorganized sidebar navigation for better discoverability
264
+
265
+ ## [0.1.10] - 2026-03-03
266
+
267
+ ### Fixed
268
+
269
+ - Build: resolve @opentui/core parser.worker.js via import.meta.resolve for monorepo hoisting
270
+ - Build: output binary as `altimate-code` instead of `opencode`
271
+ - Publish: update Docker/AUR/Homebrew references from anomalyco/opencode to AltimateAI/altimate-code
272
+ - Publish: make Docker/AUR/Homebrew steps non-fatal
273
+ - Bin wrapper: look for `@altimateai/altimate-code-*` scoped platform packages
274
+ - Postinstall: resolve `@altimateai` scoped platform packages
275
+ - Dockerfile: update binary paths and names
276
+
277
+ ## [0.1.9] - 2026-03-02
278
+
279
+ ### Fixed
280
+
281
+ - Build: fix solid-plugin import to use bare specifier for monorepo hoisting
282
+ - CI: install warehouse extras for Python tests (duckdb, boto3, etc.)
283
+ - CI: restrict pytest collection to tests/ directory
284
+ - CI: fix all ruff lint errors in Python engine
285
+ - CI: fix remaining TypeScript test failures (agent rename, config URLs, Pydantic model)
286
+ - Update theme schema URLs and documentation references to altimate-code.dev
287
+
288
+ ## [0.1.8] - 2026-03-02
289
+
290
+ ### Changed
291
+
292
+ - Rename npm scope from `@altimate` to `@altimateai` for all packages
293
+ - Wrapper package is now `@altimateai/altimate-code` (no `-ai` suffix)
294
+
295
+ ### Fixed
296
+
297
+ - CI: test fixture writes config to correct filename (`altimate-code.json`)
298
+ - CI: add `dev` optional dependency group to Python engine for pytest/ruff
299
+
300
+ ## [0.1.7] - 2026-03-02
301
+
302
+ ### Changed
303
+
304
+ - Improve TUI logo readability: redesign M, E, T, I letter shapes
305
+ - Add two-tone logo color: ALTIMATE in peach, CODE in purple
306
+
307
+ ### Fixed
308
+
309
+ - Release: npm publish glob now finds scoped package directories
310
+ - Release: PyPI publish skips existing versions instead of failing
311
+
312
+ ## [0.1.5] - 2026-03-02
313
+
314
+ ### Added
315
+
316
+ - Anthropic OAuth plugin ported in-tree
317
+ - Docs site switched from Jekyll to Material for MkDocs
318
+
319
+ ### Fixed
320
+
321
+ - Build script: restore `.trim()` on models API JSON to prevent syntax error in generated `models-snapshot.ts`
322
+ - Build script: fix archive path for scoped package names in release tarball/zip creation
323
+
324
+ ## [0.1.0] - 2025-06-01
325
+
326
+ ### Added
327
+
328
+ - Initial open-source release
329
+ - SQL analysis and formatting via Python engine
330
+ - Column-level lineage tracking
331
+ - dbt integration (profiles, lineage, `+` operator)
332
+ - Warehouse connectivity (Snowflake, BigQuery, Databricks, Postgres, DuckDB, MySQL)
333
+ - AI-powered SQL code review
334
+ - TUI interface with Solid.js
335
+ - MCP (Model Context Protocol) server support
336
+ - Auto-bootstrapping Python engine via uv
package/LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Altimate AI
4
+ Copyright (c) 2025 opencode
5
+
6
+ Permission is hereby granted, free of charge, to any person obtaining a copy
7
+ of this software and associated documentation files (the "Software"), to deal
8
+ in the Software without restriction, including without limitation the rights
9
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10
+ copies of the Software, and to permit persons to whom the Software is
11
+ furnished to do so, subject to the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be included in all
14
+ copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,235 @@
1
+ <div align="center">
2
+
3
+ <picture>
4
+ <source media="(prefers-color-scheme: dark)" srcset="docs/docs/assets/images/altimate-code-banner.png" />
5
+ <img src="docs/docs/assets/images/altimate-code-banner.png" alt="altimate-code" width="600" />
6
+ </picture>
7
+
8
+ **The open-source data engineering harness.**
9
+
10
+ The intelligence layer for data engineering AI — 99+ deterministic tools for SQL analysis,
11
+ column-level lineage, dbt, FinOps, and warehouse connectivity across every major cloud platform.
12
+
13
+ Run standalone in your terminal, embed underneath Claude Code or Codex, or integrate
14
+ into CI pipelines and orchestration DAGs. Precision data tooling for any LLM.
15
+
16
+ [![npm](https://img.shields.io/npm/v/@altimateai/altimate-code)](https://www.npmjs.com/package/@altimateai/altimate-code)
17
+ [![npm](https://img.shields.io/npm/v/@altimateai/altimate-core)](https://www.npmjs.com/package/@altimateai/altimate-core)
18
+ [![npm downloads](https://img.shields.io/npm/dm/@altimateai/altimate-code)](https://www.npmjs.com/package/@altimateai/altimate-code)
19
+ [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](./LICENSE)
20
+ [![CI](https://github.com/AltimateAI/altimate-code/actions/workflows/ci.yml/badge.svg)](https://github.com/AltimateAI/altimate-code/actions/workflows/ci.yml)
21
+ [![Slack](https://img.shields.io/badge/Slack-Join%20Community-4A154B?logo=slack)](https://altimate.ai/slack)
22
+ [![Docs](https://img.shields.io/badge/docs-altimateai.github.io-blue)](https://altimateai.github.io/altimate-code)
23
+
24
+ </div>
25
+
26
+ ---
27
+
28
+ ## Install
29
+
30
+ ```bash
31
+ # npm (recommended)
32
+ npm install -g @altimateai/altimate-code
33
+
34
+ # Homebrew
35
+ brew install AltimateAI/tap/altimate-code
36
+ ```
37
+
38
+ Then — in order:
39
+
40
+ **Step 1: Configure your LLM provider** (required before anything works):
41
+ ```bash
42
+ altimate # Launch the TUI
43
+ /connect # Interactive setup — choose your provider and enter your API key
44
+ ```
45
+
46
+ > **No API key?** Select **Codex** in the `/connect` menu — it's built-in and requires no setup.
47
+
48
+ Or set an environment variable directly:
49
+ ```bash
50
+ export ANTHROPIC_API_KEY=your_key # Anthropic Claude
51
+ export OPENAI_API_KEY=your_key # OpenAI
52
+ ```
53
+
54
+ **Step 2 (optional): Auto-detect your data stack** (read-only, safe for production connections):
55
+ ```bash
56
+ altimate /discover
57
+ ```
58
+
59
+ `/discover` auto-detects dbt projects, warehouse connections (from `~/.dbt/profiles.yml`, Docker, environment variables), and installed tools (dbt, sqlfluff, airflow, dagster, and more). Skip this and start building — you can always run it later.
60
+
61
+ > **Zero Python setup required.** On first run, the CLI automatically downloads [`uv`](https://github.com/astral-sh/uv), creates an isolated Python environment, and installs the data engine with all warehouse drivers. No `pip install`, no virtualenv management.
62
+
63
+ ## Why a specialized harness?
64
+
65
+ General AI coding agents can edit SQL files. They cannot *understand* your data stack.
66
+ altimate gives any LLM a deterministic data engineering intelligence layer —
67
+ no hallucinated SQL advice, no guessing at schema, no missed PII.
68
+
69
+ | Capability | General coding agents | altimate |
70
+ |---|---|---|
71
+ | SQL anti-pattern detection | None | 19 rules, confidence-scored |
72
+ | Column-level lineage | None | Automatic from SQL, any dialect |
73
+ | Schema-aware autocomplete | None | Live-indexed warehouse metadata |
74
+ | Cross-dialect SQL translation | None | Snowflake ↔ BigQuery ↔ Databricks ↔ Redshift |
75
+ | FinOps & cost analysis | None | Credits, expensive queries, right-sizing |
76
+ | PII detection | None | 30+ regex patterns, 15 categories |
77
+ | dbt integration | Basic file editing | Manifest parsing, test gen, model scaffolding, lineage |
78
+ | Data visualization | None | Auto-generated charts from SQL results |
79
+ | Observability | None | Local-first tracing of AI sessions and tool calls |
80
+
81
+ > **Benchmarked precision:** 100% F1 on SQL anti-pattern detection (1,077 queries, 19 rules, 0 false positives).
82
+ > 100% edge-match on column-level lineage (500 queries, 13 categories).
83
+ > [See methodology →](experiments/BENCHMARKS.md)
84
+
85
+ **What the harness provides:**
86
+ - **SQL Intelligence Engine** — deterministic SQL parsing and analysis (not LLM pattern matching). 19 rules, 100% F1, 0 false positives. Built for data engineers who've been burned by hallucinated SQL advice.
87
+ - **Column-Level Lineage** — automatic extraction from SQL across dialects. 100% edge-match on 500 benchmark queries.
88
+ - **Live Warehouse Intelligence** — indexed schemas, query history, and cost data from your actual warehouse. Not guesses.
89
+ - **dbt Native** — manifest parsing, test generation, model scaffolding, medallion patterns, impact analysis
90
+ - **FinOps** — credit consumption, expensive query detection, warehouse right-sizing, idle resource cleanup
91
+ - **PII Detection** — 15 categories, 30+ regex patterns, enforced pre-execution
92
+
93
+ **Works seamlessly with Claude Code and Codex.** altimate is the data engineering tool layer — use it standalone in your terminal, or mount it as the harness underneath whatever AI agent you already run. The two are complementary.
94
+
95
+ altimate is a fork of [OpenCode](https://github.com/anomalyco/opencode) rebuilt for data teams. Model-agnostic — bring your own LLM or run locally with Ollama.
96
+
97
+ ## Quick demo
98
+
99
+ ```bash
100
+ # Auto-detect your data stack (dbt projects, warehouse connections, installed tools)
101
+ > /discover
102
+
103
+ # Analyze a query for anti-patterns and optimization opportunities
104
+ > Analyze this query for issues: SELECT * FROM orders JOIN customers ON orders.id = customers.order_id
105
+
106
+ # Translate SQL across dialects
107
+ > /sql-translate this Snowflake query to BigQuery: SELECT DATEADD(day, 7, current_date())
108
+
109
+ # Generate dbt tests for a model
110
+ > /generate-tests for models/staging/stg_orders.sql
111
+
112
+ # Get a cost report for your Snowflake account
113
+ > /cost-report
114
+ ```
115
+
116
+ ## Key Features
117
+
118
+ All features are deterministic — they parse, trace, and measure. Not LLM pattern matching.
119
+
120
+ ### SQL Anti-Pattern Detection
121
+ 19 rules with confidence scoring — catches SELECT *, cartesian joins, non-sargable predicates, correlated subqueries, and more. **100% accuracy** on 1,077 benchmark queries.
122
+
123
+ ### Column-Level Lineage
124
+ Automatic lineage extraction from SQL. Trace any column back through joins, CTEs, and subqueries to its source. Works standalone or with dbt manifests for project-wide lineage. **100% edge match** on 500 benchmark queries.
125
+
126
+ ### FinOps & Cost Analysis
127
+ Credit analysis, expensive query detection, warehouse right-sizing, unused resource cleanup, and RBAC auditing.
128
+
129
+ ### Cross-Dialect Translation
130
+ Transpile SQL between Snowflake, BigQuery, Databricks, Redshift, PostgreSQL, MySQL, SQL Server, and DuckDB.
131
+
132
+ ### PII Detection & Safety
133
+ Automatic column scanning for PII across 15 categories with 30+ regex patterns. Safety checks and policy enforcement before query execution.
134
+
135
+ ### dbt Native
136
+ Manifest parsing, test generation, model scaffolding, incremental model detection, and lineage-aware refactoring. 12 purpose-built skills including medallion patterns, yaml config generation, and dbt docs.
137
+
138
+ ### Data Visualization
139
+ Interactive charts and dashboards from SQL results. The data-viz skill generates publication-ready visualizations with automatic chart type selection based on your data.
140
+
141
+ ### Local-First Tracing
142
+ Built-in observability for AI interactions — trace tool calls, token usage, and session activity locally. No external services required. View traces with `altimate trace`.
143
+
144
+ ### AI Teammate Training
145
+ Teach your AI teammate project-specific patterns, naming conventions, and best practices. The training system learns from examples and applies rules automatically across sessions.
146
+
147
+ ## Agent Modes
148
+
149
+ Each agent has scoped permissions and purpose-built tools for its role.
150
+
151
+ | Agent | Role | Access |
152
+ |---|---|---|
153
+ | **Builder** | Create dbt models, SQL pipelines, and data transformations | Full read/write |
154
+ | **Analyst** | Explore data, run SELECT queries, and generate insights | Read-only enforced |
155
+ | **Validator** | Data quality checks, schema validation, test coverage analysis | Read + validate |
156
+ | **Migrator** | Cross-warehouse SQL translation, schema migration, dialect conversion | Read/write for migrations |
157
+ | **Researcher** | Deep-dive analysis, documentation research, and knowledge extraction | Read-only |
158
+ | **Trainer** | Teach project-specific patterns, naming conventions, and best practices | Read + write training data |
159
+ | **Executive** | Business-audience summaries — translates findings into revenue, cost, and compliance impact | Read-only |
160
+
161
+ > **New to altimate?** Start with **Analyst mode** — it's read-only and safe to run against production connections.
162
+
163
+ ## Supported Warehouses
164
+
165
+ Snowflake · BigQuery · Databricks · PostgreSQL · Redshift · DuckDB · MySQL · SQL Server
166
+
167
+ First-class support with schema indexing, query execution, and metadata introspection. SSH tunneling available for secure connections.
168
+
169
+ ## Works with Any LLM
170
+
171
+ Model-agnostic — bring your own provider or run locally.
172
+
173
+ Anthropic · OpenAI · Google Gemini · Google Vertex AI · Amazon Bedrock · Azure OpenAI · Mistral · Groq · DeepInfra · Cerebras · Cohere · Together AI · Perplexity · xAI · OpenRouter · Ollama · GitHub Copilot
174
+
175
+ > **No API key?** **Codex** is a built-in provider with no key required. Select it via `/connect` to start immediately.
176
+
177
+ ## Skills
178
+
179
+ altimate ships with built-in skills for every common data engineering task — type `/` in the TUI to browse available skills and get autocomplete. No memorization required.
180
+
181
+ ## Architecture
182
+
183
+ ```
184
+ altimate (TypeScript CLI)
185
+ |
186
+ @altimateai/altimate-core (napi-rs → Rust)
187
+ SQL analysis, lineage, PII, safety — 45 functions, ~2ms per call
188
+ |
189
+ Native Node.js drivers
190
+ 10 warehouses: Snowflake, BigQuery, PostgreSQL, Databricks,
191
+ Redshift, MySQL, SQL Server, Oracle, DuckDB, SQLite
192
+ ```
193
+
194
+ The CLI handles AI interactions, TUI, and tool orchestration. SQL analysis is powered by the Rust-based `@altimateai/altimate-core` engine via napi-rs bindings (no Python required). Database connectivity uses native Node.js drivers with lazy loading.
195
+
196
+ **No Python dependency**: All 73 tool methods run natively in TypeScript. No pip, venv, or Python installation needed.
197
+
198
+ **dbt-first**: When working in a dbt project, the CLI automatically uses dbt's connection from `profiles.yml` — no separate warehouse configuration needed.
199
+
200
+ ### Monorepo structure
201
+
202
+ ```
203
+ packages/
204
+ altimate-code/ TypeScript CLI (main entry point)
205
+ drivers/ Shared database drivers (10 warehouses)
206
+ dbt-tools/ dbt integration (TypeScript)
207
+ plugin/ Plugin system
208
+ sdk/ SDKs (includes VS Code extension)
209
+ util/ Shared utilities
210
+ ```
211
+
212
+ ## Community & Contributing
213
+
214
+ - **Slack**: [altimate.ai/slack](https://altimate.ai/slack) — Real-time chat for questions, showcases, and feature discussion
215
+ - **Issues**: [GitHub Issues](https://github.com/AltimateAI/altimate-code/issues) — Bug reports and feature requests
216
+ - **Discussions**: [GitHub Discussions](https://github.com/AltimateAI/altimate-code/discussions) — Long-form questions and proposals
217
+ - **Security**: See [SECURITY.md](./SECURITY.md) for responsible disclosure
218
+
219
+ Contributions welcome — docs, SQL rules, warehouse connectors, and TUI improvements are all needed. The contributing guide covers setup, the vouch system, and the issue-first PR policy.
220
+
221
+ **[Read CONTRIBUTING.md →](./CONTRIBUTING.md)**
222
+
223
+ ## What's New
224
+
225
+ - **v0.4.1** (March 2026) — env-based skill selection, session caching, tracing improvements
226
+ - **v0.4.0** (Feb 2026) — data visualization skill, 99+ tools, training system
227
+ - **v0.3.x** — [See full changelog →](CHANGELOG.md)
228
+
229
+ ## License
230
+
231
+ MIT — see [LICENSE](./LICENSE).
232
+
233
+ ## Acknowledgements
234
+
235
+ altimate is a fork of [OpenCode](https://github.com/anomalyco/opencode), the open-source AI coding agent. We build on top of their excellent foundation to add data-team-specific capabilities.
package/bin/altimate ADDED
@@ -0,0 +1,223 @@
1
+ #!/usr/bin/env node
2
+
3
+ const childProcess = require("child_process")
4
+ const fs = require("fs")
5
+ const path = require("path")
6
+ const os = require("os")
7
+
8
+ // Resolve script location early — needed by both run() and findBinary().
9
+ const scriptPath = fs.realpathSync(__filename)
10
+ const scriptDir = path.dirname(scriptPath)
11
+
12
+ // Collect ALL node_modules directories walking upward from startDir.
13
+ // Bun's single-file executable uses a virtual filesystem (/$bunfs/root/) without
14
+ // node_modules. External packages are resolved via NODE_PATH instead.
15
+ // We collect every node_modules in the hierarchy (not just the first) to handle
16
+ // pnpm strict layouts, hoisted monorepos, and npm flat installs alike.
17
+ function findAllNodeModules(startDir) {
18
+ const paths = []
19
+ let current = startDir
20
+ for (;;) {
21
+ const modules = path.join(current, "node_modules")
22
+ if (fs.existsSync(modules)) paths.push(modules)
23
+ const parent = path.dirname(current)
24
+ if (parent === current) break
25
+ current = parent
26
+ }
27
+ return paths
28
+ }
29
+
30
+ function run(target) {
31
+ // Resolve NODE_PATH so the compiled Bun binary can find external packages
32
+ // installed alongside the wrapper (e.g. @altimateai/altimate-core NAPI module).
33
+ // Search from BOTH the binary's location AND the wrapper script's location
34
+ // to cover npm flat installs, pnpm isolated stores, and hoisted monorepos.
35
+ const env = { ...process.env }
36
+ try {
37
+ const resolvedTarget = fs.realpathSync(target)
38
+ const targetDir = path.dirname(path.dirname(resolvedTarget))
39
+
40
+ const targetModules = findAllNodeModules(targetDir)
41
+ const scriptModules = findAllNodeModules(scriptDir)
42
+ const allPaths = [...new Set([...scriptModules, ...targetModules])]
43
+
44
+ if (allPaths.length > 0) {
45
+ const sep = process.platform === "win32" ? ";" : ":"
46
+ const joined = allPaths.join(sep)
47
+ env.NODE_PATH = env.NODE_PATH ? joined + sep + env.NODE_PATH : joined
48
+ }
49
+ } catch {
50
+ // realpathSync failed (e.g. target doesn't exist) — continue without
51
+ // NODE_PATH; spawnSync will report the missing binary via result.error.
52
+ }
53
+
54
+ const result = childProcess.spawnSync(target, process.argv.slice(2), {
55
+ stdio: "inherit",
56
+ env,
57
+ })
58
+ if (result.error) {
59
+ console.error(result.error.message)
60
+ process.exit(1)
61
+ }
62
+ const code = typeof result.status === "number" ? result.status : 0
63
+ process.exit(code)
64
+ }
65
+
66
+ const envPath = process.env.ALTIMATE_CODE_BIN_PATH
67
+ if (envPath) {
68
+ run(envPath)
69
+ }
70
+
71
+ //
72
+ const cached = path.join(scriptDir, ".altimate-code")
73
+ if (fs.existsSync(cached)) {
74
+ run(cached)
75
+ }
76
+
77
+ const platformMap = {
78
+ darwin: "darwin",
79
+ linux: "linux",
80
+ win32: "windows",
81
+ }
82
+ const archMap = {
83
+ x64: "x64",
84
+ arm64: "arm64",
85
+ arm: "arm",
86
+ }
87
+
88
+ let platform = platformMap[os.platform()]
89
+ if (!platform) {
90
+ platform = os.platform()
91
+ }
92
+ let arch = archMap[os.arch()]
93
+ if (!arch) {
94
+ arch = os.arch()
95
+ }
96
+ const scope = "@altimateai"
97
+ const base = "altimate-code-" + platform + "-" + arch
98
+ const binary = platform === "windows" ? "altimate-code.exe" : "altimate-code"
99
+
100
+ function supportsAvx2() {
101
+ if (arch !== "x64") return false
102
+
103
+ if (platform === "linux") {
104
+ try {
105
+ return /(^|\s)avx2(\s|$)/i.test(fs.readFileSync("/proc/cpuinfo", "utf8"))
106
+ } catch {
107
+ return false
108
+ }
109
+ }
110
+
111
+ if (platform === "darwin") {
112
+ try {
113
+ const result = childProcess.spawnSync("sysctl", ["-n", "hw.optional.avx2_0"], {
114
+ encoding: "utf8",
115
+ timeout: 1500,
116
+ })
117
+ if (result.status !== 0) return false
118
+ return (result.stdout || "").trim() === "1"
119
+ } catch {
120
+ return false
121
+ }
122
+ }
123
+
124
+ if (platform === "windows") {
125
+ const cmd =
126
+ '(Add-Type -MemberDefinition "[DllImport(""kernel32.dll"")] public static extern bool IsProcessorFeaturePresent(int ProcessorFeature);" -Name Kernel32 -Namespace Win32 -PassThru)::IsProcessorFeaturePresent(40)'
127
+
128
+ for (const exe of ["powershell.exe", "pwsh.exe", "pwsh", "powershell"]) {
129
+ try {
130
+ const result = childProcess.spawnSync(exe, ["-NoProfile", "-NonInteractive", "-Command", cmd], {
131
+ encoding: "utf8",
132
+ timeout: 3000,
133
+ windowsHide: true,
134
+ })
135
+ if (result.status !== 0) continue
136
+ const out = (result.stdout || "").trim().toLowerCase()
137
+ if (out === "true" || out === "1") return true
138
+ if (out === "false" || out === "0") return false
139
+ } catch {
140
+ continue
141
+ }
142
+ }
143
+
144
+ return false
145
+ }
146
+
147
+ return false
148
+ }
149
+
150
+ const names = (() => {
151
+ const avx2 = supportsAvx2()
152
+ const baseline = arch === "x64" && !avx2
153
+
154
+ if (platform === "linux") {
155
+ const musl = (() => {
156
+ try {
157
+ if (fs.existsSync("/etc/alpine-release")) return true
158
+ } catch {
159
+ // ignore
160
+ }
161
+
162
+ try {
163
+ const result = childProcess.spawnSync("ldd", ["--version"], { encoding: "utf8" })
164
+ const text = ((result.stdout || "") + (result.stderr || "")).toLowerCase()
165
+ if (text.includes("musl")) return true
166
+ } catch {
167
+ // ignore
168
+ }
169
+
170
+ return false
171
+ })()
172
+
173
+ if (musl) {
174
+ if (arch === "x64") {
175
+ if (baseline) return [`${base}-baseline-musl`, `${base}-musl`, `${base}-baseline`, base]
176
+ return [`${base}-musl`, `${base}-baseline-musl`, base, `${base}-baseline`]
177
+ }
178
+ return [`${base}-musl`, base]
179
+ }
180
+
181
+ if (arch === "x64") {
182
+ if (baseline) return [`${base}-baseline`, base, `${base}-baseline-musl`, `${base}-musl`]
183
+ return [base, `${base}-baseline`, `${base}-musl`, `${base}-baseline-musl`]
184
+ }
185
+ return [base, `${base}-musl`]
186
+ }
187
+
188
+ if (arch === "x64") {
189
+ if (baseline) return [`${base}-baseline`, base]
190
+ return [base, `${base}-baseline`]
191
+ }
192
+ return [base]
193
+ })()
194
+
195
+ function findBinary(startDir) {
196
+ let current = startDir
197
+ for (;;) {
198
+ const modules = path.join(current, "node_modules")
199
+ if (fs.existsSync(modules)) {
200
+ for (const name of names) {
201
+ const candidate = path.join(modules, scope, name, "bin", binary)
202
+ if (fs.existsSync(candidate)) return candidate
203
+ }
204
+ }
205
+ const parent = path.dirname(current)
206
+ if (parent === current) {
207
+ return
208
+ }
209
+ current = parent
210
+ }
211
+ }
212
+
213
+ const resolved = findBinary(scriptDir)
214
+ if (!resolved) {
215
+ console.error(
216
+ "It seems that your package manager failed to install the right version of the altimate-code CLI for your platform. You can try manually installing " +
217
+ names.map((n) => `\"${scope}/${n}\"`).join(" or ") +
218
+ " package",
219
+ )
220
+ process.exit(1)
221
+ }
222
+
223
+ run(resolved)
@@ -0,0 +1,223 @@
1
+ #!/usr/bin/env node
2
+
3
+ const childProcess = require("child_process")
4
+ const fs = require("fs")
5
+ const path = require("path")
6
+ const os = require("os")
7
+
8
+ // Resolve script location early — needed by both run() and findBinary().
9
+ const scriptPath = fs.realpathSync(__filename)
10
+ const scriptDir = path.dirname(scriptPath)
11
+
12
+ // Collect ALL node_modules directories walking upward from startDir.
13
+ // Bun's single-file executable uses a virtual filesystem (/$bunfs/root/) without
14
+ // node_modules. External packages are resolved via NODE_PATH instead.
15
+ // We collect every node_modules in the hierarchy (not just the first) to handle
16
+ // pnpm strict layouts, hoisted monorepos, and npm flat installs alike.
17
+ function findAllNodeModules(startDir) {
18
+ const paths = []
19
+ let current = startDir
20
+ for (;;) {
21
+ const modules = path.join(current, "node_modules")
22
+ if (fs.existsSync(modules)) paths.push(modules)
23
+ const parent = path.dirname(current)
24
+ if (parent === current) break
25
+ current = parent
26
+ }
27
+ return paths
28
+ }
29
+
30
+ function run(target) {
31
+ // Resolve NODE_PATH so the compiled Bun binary can find external packages
32
+ // installed alongside the wrapper (e.g. @altimateai/altimate-core NAPI module).
33
+ // Search from BOTH the binary's location AND the wrapper script's location
34
+ // to cover npm flat installs, pnpm isolated stores, and hoisted monorepos.
35
+ const env = { ...process.env }
36
+ try {
37
+ const resolvedTarget = fs.realpathSync(target)
38
+ const targetDir = path.dirname(path.dirname(resolvedTarget))
39
+
40
+ const targetModules = findAllNodeModules(targetDir)
41
+ const scriptModules = findAllNodeModules(scriptDir)
42
+ const allPaths = [...new Set([...scriptModules, ...targetModules])]
43
+
44
+ if (allPaths.length > 0) {
45
+ const sep = process.platform === "win32" ? ";" : ":"
46
+ const joined = allPaths.join(sep)
47
+ env.NODE_PATH = env.NODE_PATH ? joined + sep + env.NODE_PATH : joined
48
+ }
49
+ } catch {
50
+ // realpathSync failed (e.g. target doesn't exist) — continue without
51
+ // NODE_PATH; spawnSync will report the missing binary via result.error.
52
+ }
53
+
54
+ const result = childProcess.spawnSync(target, process.argv.slice(2), {
55
+ stdio: "inherit",
56
+ env,
57
+ })
58
+ if (result.error) {
59
+ console.error(result.error.message)
60
+ process.exit(1)
61
+ }
62
+ const code = typeof result.status === "number" ? result.status : 0
63
+ process.exit(code)
64
+ }
65
+
66
+ const envPath = process.env.ALTIMATE_CODE_BIN_PATH
67
+ if (envPath) {
68
+ run(envPath)
69
+ }
70
+
71
+ //
72
+ const cached = path.join(scriptDir, ".altimate-code")
73
+ if (fs.existsSync(cached)) {
74
+ run(cached)
75
+ }
76
+
77
+ const platformMap = {
78
+ darwin: "darwin",
79
+ linux: "linux",
80
+ win32: "windows",
81
+ }
82
+ const archMap = {
83
+ x64: "x64",
84
+ arm64: "arm64",
85
+ arm: "arm",
86
+ }
87
+
88
+ let platform = platformMap[os.platform()]
89
+ if (!platform) {
90
+ platform = os.platform()
91
+ }
92
+ let arch = archMap[os.arch()]
93
+ if (!arch) {
94
+ arch = os.arch()
95
+ }
96
+ const scope = "@altimateai"
97
+ const base = "altimate-code-" + platform + "-" + arch
98
+ const binary = platform === "windows" ? "altimate-code.exe" : "altimate-code"
99
+
100
+ function supportsAvx2() {
101
+ if (arch !== "x64") return false
102
+
103
+ if (platform === "linux") {
104
+ try {
105
+ return /(^|\s)avx2(\s|$)/i.test(fs.readFileSync("/proc/cpuinfo", "utf8"))
106
+ } catch {
107
+ return false
108
+ }
109
+ }
110
+
111
+ if (platform === "darwin") {
112
+ try {
113
+ const result = childProcess.spawnSync("sysctl", ["-n", "hw.optional.avx2_0"], {
114
+ encoding: "utf8",
115
+ timeout: 1500,
116
+ })
117
+ if (result.status !== 0) return false
118
+ return (result.stdout || "").trim() === "1"
119
+ } catch {
120
+ return false
121
+ }
122
+ }
123
+
124
+ if (platform === "windows") {
125
+ const cmd =
126
+ '(Add-Type -MemberDefinition "[DllImport(""kernel32.dll"")] public static extern bool IsProcessorFeaturePresent(int ProcessorFeature);" -Name Kernel32 -Namespace Win32 -PassThru)::IsProcessorFeaturePresent(40)'
127
+
128
+ for (const exe of ["powershell.exe", "pwsh.exe", "pwsh", "powershell"]) {
129
+ try {
130
+ const result = childProcess.spawnSync(exe, ["-NoProfile", "-NonInteractive", "-Command", cmd], {
131
+ encoding: "utf8",
132
+ timeout: 3000,
133
+ windowsHide: true,
134
+ })
135
+ if (result.status !== 0) continue
136
+ const out = (result.stdout || "").trim().toLowerCase()
137
+ if (out === "true" || out === "1") return true
138
+ if (out === "false" || out === "0") return false
139
+ } catch {
140
+ continue
141
+ }
142
+ }
143
+
144
+ return false
145
+ }
146
+
147
+ return false
148
+ }
149
+
150
+ const names = (() => {
151
+ const avx2 = supportsAvx2()
152
+ const baseline = arch === "x64" && !avx2
153
+
154
+ if (platform === "linux") {
155
+ const musl = (() => {
156
+ try {
157
+ if (fs.existsSync("/etc/alpine-release")) return true
158
+ } catch {
159
+ // ignore
160
+ }
161
+
162
+ try {
163
+ const result = childProcess.spawnSync("ldd", ["--version"], { encoding: "utf8" })
164
+ const text = ((result.stdout || "") + (result.stderr || "")).toLowerCase()
165
+ if (text.includes("musl")) return true
166
+ } catch {
167
+ // ignore
168
+ }
169
+
170
+ return false
171
+ })()
172
+
173
+ if (musl) {
174
+ if (arch === "x64") {
175
+ if (baseline) return [`${base}-baseline-musl`, `${base}-musl`, `${base}-baseline`, base]
176
+ return [`${base}-musl`, `${base}-baseline-musl`, base, `${base}-baseline`]
177
+ }
178
+ return [`${base}-musl`, base]
179
+ }
180
+
181
+ if (arch === "x64") {
182
+ if (baseline) return [`${base}-baseline`, base, `${base}-baseline-musl`, `${base}-musl`]
183
+ return [base, `${base}-baseline`, `${base}-musl`, `${base}-baseline-musl`]
184
+ }
185
+ return [base, `${base}-musl`]
186
+ }
187
+
188
+ if (arch === "x64") {
189
+ if (baseline) return [`${base}-baseline`, base]
190
+ return [base, `${base}-baseline`]
191
+ }
192
+ return [base]
193
+ })()
194
+
195
+ function findBinary(startDir) {
196
+ let current = startDir
197
+ for (;;) {
198
+ const modules = path.join(current, "node_modules")
199
+ if (fs.existsSync(modules)) {
200
+ for (const name of names) {
201
+ const candidate = path.join(modules, scope, name, "bin", binary)
202
+ if (fs.existsSync(candidate)) return candidate
203
+ }
204
+ }
205
+ const parent = path.dirname(current)
206
+ if (parent === current) {
207
+ return
208
+ }
209
+ current = parent
210
+ }
211
+ }
212
+
213
+ const resolved = findBinary(scriptDir)
214
+ if (!resolved) {
215
+ console.error(
216
+ "It seems that your package manager failed to install the right version of the altimate-code CLI for your platform. You can try manually installing " +
217
+ names.map((n) => `\"${scope}/${n}\"`).join(" or ") +
218
+ " package",
219
+ )
220
+ process.exit(1)
221
+ }
222
+
223
+ run(resolved)
package/package.json CHANGED
@@ -1,10 +1,36 @@
1
1
  {
2
2
  "name": "altimate-code",
3
- "version": "0.0.1",
4
- "description": "The data engineering agent for dbt, SQL, and cloud warehouses.",
5
- "license": "MIT",
3
+ "description": "The AI-native data engineering agent for the terminal",
6
4
  "repository": {
7
5
  "type": "git",
8
- "url": "https://github.com/AltimateAI/altimate-code"
6
+ "url": "git+https://github.com/AltimateAI/altimate-code.git"
7
+ },
8
+ "homepage": "https://github.com/AltimateAI/altimate-code#readme",
9
+ "bugs": "https://github.com/AltimateAI/altimate-code/issues",
10
+ "bin": {
11
+ "altimate": "./bin/altimate",
12
+ "altimate-code": "./bin/altimate-code"
13
+ },
14
+ "scripts": {
15
+ "postinstall": "bun ./postinstall.mjs || node ./postinstall.mjs"
16
+ },
17
+ "version": "v0.4.9",
18
+ "license": "MIT",
19
+ "dependencies": {
20
+ "@altimateai/altimate-core": "^0.2.3"
21
+ },
22
+ "optionalDependencies": {
23
+ "@altimateai/altimate-code-linux-x64": "v0.4.9",
24
+ "@altimateai/altimate-code-windows-arm64": "v0.4.9",
25
+ "@altimateai/altimate-code-linux-arm64-musl": "v0.4.9",
26
+ "@altimateai/altimate-code-darwin-x64": "v0.4.9",
27
+ "@altimateai/altimate-code-windows-x64": "v0.4.9",
28
+ "@altimateai/altimate-code-linux-x64-musl": "v0.4.9",
29
+ "@altimateai/altimate-code-darwin-x64-baseline": "v0.4.9",
30
+ "@altimateai/altimate-code-linux-x64-baseline-musl": "v0.4.9",
31
+ "@altimateai/altimate-code-linux-x64-baseline": "v0.4.9",
32
+ "@altimateai/altimate-code-linux-arm64": "v0.4.9",
33
+ "@altimateai/altimate-code-darwin-arm64": "v0.4.9",
34
+ "@altimateai/altimate-code-windows-x64-baseline": "v0.4.9"
9
35
  }
10
- }
36
+ }
@@ -0,0 +1,175 @@
1
+ #!/usr/bin/env node
2
+
3
+ import fs from "fs"
4
+ import path from "path"
5
+ import os from "os"
6
+ import { fileURLToPath } from "url"
7
+ import { createRequire } from "module"
8
+
9
+ const __dirname = path.dirname(fileURLToPath(import.meta.url))
10
+ const require = createRequire(import.meta.url)
11
+
12
+ function detectPlatformAndArch() {
13
+ // Map platform names
14
+ let platform
15
+ switch (os.platform()) {
16
+ case "darwin":
17
+ platform = "darwin"
18
+ break
19
+ case "linux":
20
+ platform = "linux"
21
+ break
22
+ case "win32":
23
+ platform = "windows"
24
+ break
25
+ default:
26
+ platform = os.platform()
27
+ break
28
+ }
29
+
30
+ // Map architecture names
31
+ let arch
32
+ switch (os.arch()) {
33
+ case "x64":
34
+ arch = "x64"
35
+ break
36
+ case "arm64":
37
+ arch = "arm64"
38
+ break
39
+ case "arm":
40
+ arch = "arm"
41
+ break
42
+ default:
43
+ arch = os.arch()
44
+ break
45
+ }
46
+
47
+ return { platform, arch }
48
+ }
49
+
50
+ function findBinary() {
51
+ const { platform, arch } = detectPlatformAndArch()
52
+ const packageName = `@altimateai/altimate-code-${platform}-${arch}`
53
+ const binaryName = platform === "windows" ? "altimate-code.exe" : "altimate-code"
54
+
55
+ try {
56
+ // Use require.resolve to find the package
57
+ const packageJsonPath = require.resolve(`${packageName}/package.json`)
58
+ const packageDir = path.dirname(packageJsonPath)
59
+ const binaryPath = path.join(packageDir, "bin", binaryName)
60
+
61
+ if (!fs.existsSync(binaryPath)) {
62
+ throw new Error(`Binary not found at ${binaryPath}`)
63
+ }
64
+
65
+ return { binaryPath, binaryName }
66
+ } catch (error) {
67
+ throw new Error(`Could not find package ${packageName}: ${error.message}`)
68
+ }
69
+ }
70
+
71
+ function prepareBinDirectory(binaryName) {
72
+ const binDir = path.join(__dirname, "bin")
73
+ const targetPath = path.join(binDir, binaryName)
74
+
75
+ // Ensure bin directory exists
76
+ if (!fs.existsSync(binDir)) {
77
+ fs.mkdirSync(binDir, { recursive: true })
78
+ }
79
+
80
+ // Remove existing binary/symlink if it exists
81
+ if (fs.existsSync(targetPath)) {
82
+ fs.unlinkSync(targetPath)
83
+ }
84
+
85
+ return { binDir, targetPath }
86
+ }
87
+
88
+ function printWelcome(version) {
89
+ const cleanVersion = version.replace(/^v/, "")
90
+ const v = `altimate-code v${cleanVersion} installed`
91
+ const lines = [
92
+ "",
93
+ " Get started:",
94
+ " altimate Open the TUI",
95
+ ' altimate run "hello" Run a quick task',
96
+ " altimate --help See all commands",
97
+ "",
98
+ " Docs: https://altimate-code.dev",
99
+ "",
100
+ ]
101
+ // Box width: pad all lines to the same length
102
+ const contentWidth = Math.max(v.length, ...lines.map((l) => l.length)) + 2
103
+ const pad = (s) => s + " ".repeat(contentWidth - s.length)
104
+ const top = ` ╭${"─".repeat(contentWidth + 2)}╮`
105
+ const bot = ` ╰${"─".repeat(contentWidth + 2)}╯`
106
+ const empty = ` │ ${" ".repeat(contentWidth)} │`
107
+ const row = (s) => ` │ ${pad(s)} │`
108
+
109
+ // Use stderr — npm v7+ silences postinstall stdout
110
+ const out = (s) => process.stderr.write(s + "\n")
111
+ out(top)
112
+ out(empty)
113
+ out(row(` ${v}`))
114
+ for (const line of lines) out(row(line))
115
+ out(bot)
116
+ }
117
+
118
+ /**
119
+ * Write a marker file so the CLI can show a welcome/upgrade banner on first run.
120
+ * npm v7+ silences postinstall stdout, so the CLI reads this marker at startup instead.
121
+ */
122
+ function writeUpgradeMarker(version) {
123
+ try {
124
+ const xdgData = process.env.XDG_DATA_HOME || path.join(os.homedir(), ".local", "share")
125
+ const dataDir = path.join(xdgData, "altimate-code")
126
+ fs.mkdirSync(dataDir, { recursive: true })
127
+ fs.writeFileSync(path.join(dataDir, ".installed-version"), version.replace(/^v/, ""))
128
+ } catch {
129
+ // Non-fatal — the CLI just won't show a welcome banner
130
+ }
131
+ }
132
+
133
+ async function main() {
134
+ let version
135
+ try {
136
+ const pkgPath = path.join(__dirname, "package.json")
137
+ if (fs.existsSync(pkgPath)) {
138
+ version = JSON.parse(fs.readFileSync(pkgPath, "utf-8")).version
139
+ }
140
+ } catch {}
141
+
142
+ try {
143
+ if (os.platform() === "win32") {
144
+ // On Windows, the .exe is already included in the package and bin field points to it
145
+ // No postinstall setup needed
146
+ if (version) writeUpgradeMarker(version)
147
+ return
148
+ }
149
+
150
+ // On non-Windows platforms, just verify the binary package exists
151
+ // Don't replace the wrapper script - it handles binary execution
152
+ const { binaryPath } = findBinary()
153
+ const target = path.join(__dirname, "bin", ".altimate-code")
154
+ if (fs.existsSync(target)) fs.unlinkSync(target)
155
+ try {
156
+ fs.linkSync(binaryPath, target)
157
+ } catch {
158
+ fs.copyFileSync(binaryPath, target)
159
+ }
160
+ fs.chmodSync(target, 0o755)
161
+ // Write marker only — npm v7+ suppresses all postinstall output.
162
+ // The CLI picks up the marker and shows the welcome box on first run.
163
+ if (version) writeUpgradeMarker(version)
164
+ } catch (error) {
165
+ console.error("Failed to setup altimate-code binary:", error.message)
166
+ process.exit(1)
167
+ }
168
+ }
169
+
170
+ try {
171
+ main()
172
+ } catch (error) {
173
+ console.error("Postinstall script error:", error.message)
174
+ process.exit(0)
175
+ }