altimate-code 0.0.1 → 0.4.7
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 +316 -0
- package/LICENSE +22 -0
- package/README.md +235 -0
- package/bin/altimate +180 -0
- package/bin/altimate-code +180 -0
- package/package.json +28 -5
- package/postinstall.mjs +175 -0
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,316 @@
|
|
|
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.1] - 2026-03-16
|
|
9
|
+
## [0.4.2] - 2026-03-18
|
|
10
|
+
|
|
11
|
+
### Breaking Changes
|
|
12
|
+
|
|
13
|
+
- **Python engine eliminated** — all 73 tool methods now run natively in TypeScript. No Python, pip, venv, or `altimate-engine` installation required. Fixes #210.
|
|
14
|
+
|
|
15
|
+
### Added
|
|
16
|
+
|
|
17
|
+
- `@altimateai/drivers` shared workspace package with 10 database drivers (Snowflake, BigQuery, PostgreSQL, Databricks, Redshift, MySQL, SQL Server, Oracle, DuckDB, SQLite)
|
|
18
|
+
- Direct `@altimateai/altimate-core` napi-rs bindings — SQL analysis calls go straight to Rust (no Python intermediary)
|
|
19
|
+
- dbt-first SQL execution — automatically uses `profiles.yml` connection when in a dbt project
|
|
20
|
+
- Warehouse telemetry (5 event types: connect, query, introspection, discovery, census)
|
|
21
|
+
- 340+ new tests including E2E tests against live Snowflake, BigQuery, and Databricks accounts
|
|
22
|
+
- Encrypted key-pair auth support for Snowflake (PKCS8 PEM with passphrase)
|
|
23
|
+
- Comprehensive driver documentation at `docs/docs/drivers.md`
|
|
24
|
+
|
|
25
|
+
### Fixed
|
|
26
|
+
|
|
27
|
+
- Python bridge connection failures for UV, conda, and non-standard venv setups (#210)
|
|
28
|
+
- SQL injection in finops/schema queries (parameterized queries + escape utility)
|
|
29
|
+
- Credential store no longer saves plaintext passwords
|
|
30
|
+
- SSH tunnel cleanup on SIGINT/SIGTERM
|
|
31
|
+
- Race condition in connection registry for concurrent access
|
|
32
|
+
- Databricks DATE_SUB syntax
|
|
33
|
+
- Redshift describeTable column name
|
|
34
|
+
- SQL Server describeTable includes views
|
|
35
|
+
- Dispatcher telemetry wrapped in try/catch
|
|
36
|
+
- Flaky test timeouts
|
|
37
|
+
|
|
38
|
+
### Removed
|
|
39
|
+
|
|
40
|
+
- `packages/altimate-engine/` — entire Python package (~17,000 lines)
|
|
41
|
+
- `packages/opencode/src/altimate/bridge/` — JSON-RPC bridge
|
|
42
|
+
- `.github/workflows/publish-engine.yml` — PyPI publish workflow
|
|
43
|
+
|
|
44
|
+
### Added
|
|
45
|
+
|
|
46
|
+
- Local-first tracing system replacing Langfuse (#183)
|
|
47
|
+
|
|
48
|
+
### Fixed
|
|
49
|
+
|
|
50
|
+
- Engine not found when user's project has `.venv` in cwd — managed venv now takes priority (#199)
|
|
51
|
+
- Missing `[warehouses]` pip extra causing FinOps tools to fail with "snowflake-connector-python not installed" (#199)
|
|
52
|
+
- Engine install trusting stale manifest when venv/Python binary was deleted (#199)
|
|
53
|
+
- Extras changes not detected on upgrade — manifest now tracks installed extras (#199)
|
|
54
|
+
- Windows path handling for dev/cwd venv resolution (#199)
|
|
55
|
+
- Concurrent bridge startup race condition — added `pendingStart` mutex (#199)
|
|
56
|
+
- Unhandled spawn `error` event crashing host process on invalid Python path (#199)
|
|
57
|
+
- Bridge hung permanently after ping failure — child process now cleaned up (#199)
|
|
58
|
+
- `restartCount` incorrectly incremented on signal kills, prematurely disabling bridge (#199)
|
|
59
|
+
- TUI prompt corruption from engine bootstrap messages writing to stderr (#180)
|
|
60
|
+
- Tracing exporter timeout leaking timers (#191)
|
|
61
|
+
- Feedback submission failing when repo labels don't exist (#188)
|
|
62
|
+
- Pre-release security and resource cleanup fixes for tracing (#197)
|
|
63
|
+
|
|
64
|
+
## [0.4.0] - 2026-03-15
|
|
65
|
+
|
|
66
|
+
### Added
|
|
67
|
+
|
|
68
|
+
- Data-viz skill for data storytelling and visualizations (#170)
|
|
69
|
+
- AI Teammate training system with learn-by-example patterns (#148)
|
|
70
|
+
|
|
71
|
+
### Fixed
|
|
72
|
+
|
|
73
|
+
- Sidebar shows "OpenCode" instead of "Altimate Code" after upstream merge (#168)
|
|
74
|
+
- Prevent upstream tags from polluting origin (#165)
|
|
75
|
+
- Show welcome box on first CLI run, not during postinstall (#163)
|
|
76
|
+
|
|
77
|
+
### Changed
|
|
78
|
+
|
|
79
|
+
- Engine version bumped to 0.4.0
|
|
80
|
+
|
|
81
|
+
## [0.3.1] - 2026-03-15
|
|
82
|
+
|
|
83
|
+
### Fixed
|
|
84
|
+
|
|
85
|
+
- Database migration crash when upgrading from v0.2.x — backfill NULL migration names for Drizzle beta.16 compatibility (#161)
|
|
86
|
+
- Install banner not visible during `npm install` — moved output from stdout to stderr (#161)
|
|
87
|
+
- Verbose changelog dump removed from CLI startup (#161)
|
|
88
|
+
- `altimate upgrade` detection broken — `method()` and `latest()` referenced upstream `opencode-ai` package names instead of `@altimateai/altimate-code` (#161)
|
|
89
|
+
- Brew formula detection and upgrade referencing `opencode` instead of `altimate-code` (#161)
|
|
90
|
+
- Homebrew tap updated to v0.3.0 (was stuck at 0.1.4 due to expired `HOMEBREW_TAP_TOKEN`) (#161)
|
|
91
|
+
- `.opencode/memory/` references in docs updated to `.altimate-code/memory/` (#161)
|
|
92
|
+
- Stale `@opencode-ai/plugin` reference in CONTRIBUTING.md (#161)
|
|
93
|
+
|
|
94
|
+
### Changed
|
|
95
|
+
|
|
96
|
+
- CI now uses path-based change detection to skip unaffected jobs (saves ~100s on non-TS changes) (#161)
|
|
97
|
+
- Release workflow gated on test job passing (#157)
|
|
98
|
+
- Upstream merge restricted to published GitHub releases only (#150)
|
|
99
|
+
|
|
100
|
+
## [0.3.0] - 2026-03-15
|
|
101
|
+
|
|
102
|
+
### Added
|
|
103
|
+
|
|
104
|
+
- AI-powered prompt enhancement (#144)
|
|
105
|
+
- Altimate Memory — persistent cross-session memory with TTL, namespaces, citations, and audit logging (#136)
|
|
106
|
+
- Upstream merge with OpenCode v1.2.26 (#142)
|
|
107
|
+
|
|
108
|
+
### Fixed
|
|
109
|
+
|
|
110
|
+
- Sentry review findings from PR #144 (#147)
|
|
111
|
+
- OAuth token refresh retry and error handling for idle timeout (#133)
|
|
112
|
+
- Welcome banner on first CLI run after install/upgrade (#132)
|
|
113
|
+
- `@altimateai/altimate-code` npm package name restored after upstream rebase
|
|
114
|
+
- Replace `mock.module()` with `spyOn()` to fix 149 test failures (#153)
|
|
115
|
+
|
|
116
|
+
### Changed
|
|
117
|
+
|
|
118
|
+
- Rebrand user-facing references to Altimate Code (#134)
|
|
119
|
+
- Bump `@modelcontextprotocol/sdk` dependency (#139)
|
|
120
|
+
- Engine version bumped to 0.3.0
|
|
121
|
+
|
|
122
|
+
## [0.2.5] - 2026-03-13
|
|
123
|
+
|
|
124
|
+
### Added
|
|
125
|
+
|
|
126
|
+
- `/feedback` command and `feedback_submit` tool for in-app user feedback (#89)
|
|
127
|
+
- Datamate manager — dynamic MCP server management (#99)
|
|
128
|
+
- Non-interactive mode for `mcp add` command with input validation
|
|
129
|
+
- `mcp remove` command
|
|
130
|
+
- Upstream merge with OpenCode v1.2.20
|
|
131
|
+
|
|
132
|
+
### Fixed
|
|
133
|
+
|
|
134
|
+
- TUI crash after upstream merge (#98)
|
|
135
|
+
- `GitlabAuthPlugin` type incompatibility in plugin loader (#92)
|
|
136
|
+
- All test failures from fork restructure (#91)
|
|
137
|
+
- CI/CD workflow paths updated from `altimate-code` to `opencode`
|
|
138
|
+
- Fallback to global config when not in a git repo
|
|
139
|
+
- PR standards workflow `TEAM_MEMBERS` ref corrected from `dev` to `main` (#101)
|
|
140
|
+
|
|
141
|
+
### Changed
|
|
142
|
+
|
|
143
|
+
- Removed self-hosted runners from public repo CI (#110)
|
|
144
|
+
- Migrated CI/release to ARC runners (#93, #94)
|
|
145
|
+
- Reverted Windows tests to `windows-latest` (#95)
|
|
146
|
+
- Engine version bumped to 0.2.5
|
|
147
|
+
|
|
148
|
+
## [0.2.4] - 2026-03-04
|
|
149
|
+
|
|
150
|
+
### Added
|
|
151
|
+
|
|
152
|
+
- E2E tests for npm install pipeline: postinstall script, bin wrapper, and publish output (#50)
|
|
153
|
+
|
|
154
|
+
## [0.2.3] - 2026-03-04
|
|
155
|
+
|
|
156
|
+
### Added
|
|
157
|
+
|
|
158
|
+
- Postinstall welcome banner and changelog display after upgrade (#48)
|
|
159
|
+
|
|
160
|
+
### Fixed
|
|
161
|
+
|
|
162
|
+
- Security: validate well-known auth command type before execution, add confirmation prompt (#45)
|
|
163
|
+
- CI/CD: SHA-pin all GitHub Actions, per-job least-privilege permissions (#45)
|
|
164
|
+
- MCP: fix copy-paste log messages, log init errors, prefix floating promises (#45)
|
|
165
|
+
- Session compaction: clean up compactionAttempts on abort to prevent memory leak (#45)
|
|
166
|
+
- Telemetry: retry failed flush events once with buffer-size cap (#45, #46)
|
|
167
|
+
- Telemetry: flush events before process exit (#46)
|
|
168
|
+
- TUI: resolve worker startup crash from circular dependency (#47)
|
|
169
|
+
- CLI: define ALTIMATE_CLI build-time constants for correct version reporting (#41)
|
|
170
|
+
- Address 4 issues found in post-v0.2.2 commits (#49)
|
|
171
|
+
- Address remaining code review issues from PR #39 (#43)
|
|
172
|
+
|
|
173
|
+
### Changed
|
|
174
|
+
|
|
175
|
+
- CI/CD: optimize pipeline with caching and parallel builds (#42)
|
|
176
|
+
|
|
177
|
+
### Docs
|
|
178
|
+
|
|
179
|
+
- Add security FAQ (#44)
|
|
180
|
+
|
|
181
|
+
## [0.2.2] - 2026-03-05
|
|
182
|
+
|
|
183
|
+
### Fixed
|
|
184
|
+
|
|
185
|
+
- Telemetry init: `Config.get()` failure outside Instance context no longer silently disables telemetry
|
|
186
|
+
- Telemetry init: called early in CLI middleware and worker thread so MCP/engine/auth events are captured
|
|
187
|
+
- Telemetry init: promise deduplication prevents concurrent init race conditions
|
|
188
|
+
- Telemetry: pre-init events are now buffered and flushed (previously silently dropped)
|
|
189
|
+
- Telemetry: user email is SHA-256 hashed before sending (privacy)
|
|
190
|
+
- Telemetry: error message truncation standardized to 500 chars across all event types
|
|
191
|
+
- Telemetry: `ALTIMATE_TELEMETRY_DISABLED` env var now actually checked in init
|
|
192
|
+
- Telemetry: MCP disconnect reports correct transport type instead of hardcoded `stdio`
|
|
193
|
+
- Telemetry: `agent_outcome` now correctly reports `"error"` outcome for failed sessions
|
|
194
|
+
|
|
195
|
+
### Changed
|
|
196
|
+
|
|
197
|
+
- Auth telemetry events use session context when available instead of hardcoded `"cli"`
|
|
198
|
+
|
|
199
|
+
## [0.2.1] - 2026-03-05
|
|
200
|
+
|
|
201
|
+
### Added
|
|
202
|
+
|
|
203
|
+
- 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
|
|
204
|
+
- Telemetry docs page with event table, privacy policy, opt-out instructions, and contributor guide
|
|
205
|
+
- AppInsights endpoint added to network firewall documentation
|
|
206
|
+
- `categorizeToolName()` helper for tool classification (sql, schema, dbt, finops, warehouse, lineage, file, mcp)
|
|
207
|
+
- `bucketCount()` helper for privacy-safe count bucketing
|
|
208
|
+
|
|
209
|
+
### Fixed
|
|
210
|
+
|
|
211
|
+
- Command loading made resilient to MCP/Skill initialization failures
|
|
212
|
+
|
|
213
|
+
### Changed
|
|
214
|
+
|
|
215
|
+
- CLI binary renamed from `altimate-code` to `altimate`
|
|
216
|
+
|
|
217
|
+
## [0.2.0] - 2026-03-04
|
|
218
|
+
|
|
219
|
+
### Added
|
|
220
|
+
|
|
221
|
+
- Context management: auto-compaction with overflow recovery, observation masking, and loop protection
|
|
222
|
+
- Context management: data-engineering-aware compaction template preserving warehouse, schema, dbt, and lineage context
|
|
223
|
+
- Context management: content-aware token estimation (code, JSON, SQL, text heuristics)
|
|
224
|
+
- Context management: observation masking replaces pruned tool outputs with fingerprinted summaries
|
|
225
|
+
- Context management: provider overflow detection for Azure OpenAI patterns
|
|
226
|
+
- CLI observability: telemetry module with session, generation, tool call, and error tracking
|
|
227
|
+
- `/discover` command for data stack setup with project_scan tool
|
|
228
|
+
- User documentation for context management configuration
|
|
229
|
+
|
|
230
|
+
### Fixed
|
|
231
|
+
|
|
232
|
+
- ContextOverflowError now triggers automatic compaction instead of a dead-end error
|
|
233
|
+
- `isOverflow()` correctly reserves headroom for models with separate input/output limits
|
|
234
|
+
- `NamedError.isInstance()` no longer crashes on null input
|
|
235
|
+
- Text part duration tracking now preserves original start timestamp
|
|
236
|
+
- Compaction loop protection: max 3 consecutive attempts per turn, counter resets between turns
|
|
237
|
+
- Negative usable context guard for models where headroom exceeds base capacity
|
|
238
|
+
|
|
239
|
+
### Changed
|
|
240
|
+
|
|
241
|
+
- Removed cost estimation and complexity scoring bindings
|
|
242
|
+
- Docs: redesigned homepage with hero, feature cards, and pill layouts
|
|
243
|
+
- Docs: reorganized sidebar navigation for better discoverability
|
|
244
|
+
|
|
245
|
+
## [0.1.10] - 2026-03-03
|
|
246
|
+
|
|
247
|
+
### Fixed
|
|
248
|
+
|
|
249
|
+
- Build: resolve @opentui/core parser.worker.js via import.meta.resolve for monorepo hoisting
|
|
250
|
+
- Build: output binary as `altimate-code` instead of `opencode`
|
|
251
|
+
- Publish: update Docker/AUR/Homebrew references from anomalyco/opencode to AltimateAI/altimate-code
|
|
252
|
+
- Publish: make Docker/AUR/Homebrew steps non-fatal
|
|
253
|
+
- Bin wrapper: look for `@altimateai/altimate-code-*` scoped platform packages
|
|
254
|
+
- Postinstall: resolve `@altimateai` scoped platform packages
|
|
255
|
+
- Dockerfile: update binary paths and names
|
|
256
|
+
|
|
257
|
+
## [0.1.9] - 2026-03-02
|
|
258
|
+
|
|
259
|
+
### Fixed
|
|
260
|
+
|
|
261
|
+
- Build: fix solid-plugin import to use bare specifier for monorepo hoisting
|
|
262
|
+
- CI: install warehouse extras for Python tests (duckdb, boto3, etc.)
|
|
263
|
+
- CI: restrict pytest collection to tests/ directory
|
|
264
|
+
- CI: fix all ruff lint errors in Python engine
|
|
265
|
+
- CI: fix remaining TypeScript test failures (agent rename, config URLs, Pydantic model)
|
|
266
|
+
- Update theme schema URLs and documentation references to altimate-code.dev
|
|
267
|
+
|
|
268
|
+
## [0.1.8] - 2026-03-02
|
|
269
|
+
|
|
270
|
+
### Changed
|
|
271
|
+
|
|
272
|
+
- Rename npm scope from `@altimate` to `@altimateai` for all packages
|
|
273
|
+
- Wrapper package is now `@altimateai/altimate-code` (no `-ai` suffix)
|
|
274
|
+
|
|
275
|
+
### Fixed
|
|
276
|
+
|
|
277
|
+
- CI: test fixture writes config to correct filename (`altimate-code.json`)
|
|
278
|
+
- CI: add `dev` optional dependency group to Python engine for pytest/ruff
|
|
279
|
+
|
|
280
|
+
## [0.1.7] - 2026-03-02
|
|
281
|
+
|
|
282
|
+
### Changed
|
|
283
|
+
|
|
284
|
+
- Improve TUI logo readability: redesign M, E, T, I letter shapes
|
|
285
|
+
- Add two-tone logo color: ALTIMATE in peach, CODE in purple
|
|
286
|
+
|
|
287
|
+
### Fixed
|
|
288
|
+
|
|
289
|
+
- Release: npm publish glob now finds scoped package directories
|
|
290
|
+
- Release: PyPI publish skips existing versions instead of failing
|
|
291
|
+
|
|
292
|
+
## [0.1.5] - 2026-03-02
|
|
293
|
+
|
|
294
|
+
### Added
|
|
295
|
+
|
|
296
|
+
- Anthropic OAuth plugin ported in-tree
|
|
297
|
+
- Docs site switched from Jekyll to Material for MkDocs
|
|
298
|
+
|
|
299
|
+
### Fixed
|
|
300
|
+
|
|
301
|
+
- Build script: restore `.trim()` on models API JSON to prevent syntax error in generated `models-snapshot.ts`
|
|
302
|
+
- Build script: fix archive path for scoped package names in release tarball/zip creation
|
|
303
|
+
|
|
304
|
+
## [0.1.0] - 2025-06-01
|
|
305
|
+
|
|
306
|
+
### Added
|
|
307
|
+
|
|
308
|
+
- Initial open-source release
|
|
309
|
+
- SQL analysis and formatting via Python engine
|
|
310
|
+
- Column-level lineage tracking
|
|
311
|
+
- dbt integration (profiles, lineage, `+` operator)
|
|
312
|
+
- Warehouse connectivity (Snowflake, BigQuery, Databricks, Postgres, DuckDB, MySQL)
|
|
313
|
+
- AI-powered SQL code review
|
|
314
|
+
- TUI interface with Solid.js
|
|
315
|
+
- MCP (Model Context Protocol) server support
|
|
316
|
+
- 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
|
+
[](https://www.npmjs.com/package/@altimateai/altimate-code)
|
|
17
|
+
[](https://www.npmjs.com/package/@altimateai/altimate-core)
|
|
18
|
+
[](https://www.npmjs.com/package/@altimateai/altimate-code)
|
|
19
|
+
[](./LICENSE)
|
|
20
|
+
[](https://github.com/AltimateAI/altimate-code/actions/workflows/ci.yml)
|
|
21
|
+
[](https://altimate.ai/slack)
|
|
22
|
+
[](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,180 @@
|
|
|
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
|
+
function run(target) {
|
|
9
|
+
const result = childProcess.spawnSync(target, process.argv.slice(2), {
|
|
10
|
+
stdio: "inherit",
|
|
11
|
+
})
|
|
12
|
+
if (result.error) {
|
|
13
|
+
console.error(result.error.message)
|
|
14
|
+
process.exit(1)
|
|
15
|
+
}
|
|
16
|
+
const code = typeof result.status === "number" ? result.status : 0
|
|
17
|
+
process.exit(code)
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
const envPath = process.env.ALTIMATE_CODE_BIN_PATH
|
|
21
|
+
if (envPath) {
|
|
22
|
+
run(envPath)
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
const scriptPath = fs.realpathSync(__filename)
|
|
26
|
+
const scriptDir = path.dirname(scriptPath)
|
|
27
|
+
|
|
28
|
+
//
|
|
29
|
+
const cached = path.join(scriptDir, ".altimate-code")
|
|
30
|
+
if (fs.existsSync(cached)) {
|
|
31
|
+
run(cached)
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
const platformMap = {
|
|
35
|
+
darwin: "darwin",
|
|
36
|
+
linux: "linux",
|
|
37
|
+
win32: "windows",
|
|
38
|
+
}
|
|
39
|
+
const archMap = {
|
|
40
|
+
x64: "x64",
|
|
41
|
+
arm64: "arm64",
|
|
42
|
+
arm: "arm",
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
let platform = platformMap[os.platform()]
|
|
46
|
+
if (!platform) {
|
|
47
|
+
platform = os.platform()
|
|
48
|
+
}
|
|
49
|
+
let arch = archMap[os.arch()]
|
|
50
|
+
if (!arch) {
|
|
51
|
+
arch = os.arch()
|
|
52
|
+
}
|
|
53
|
+
const scope = "@altimateai"
|
|
54
|
+
const base = "altimate-code-" + platform + "-" + arch
|
|
55
|
+
const binary = platform === "windows" ? "altimate-code.exe" : "altimate-code"
|
|
56
|
+
|
|
57
|
+
function supportsAvx2() {
|
|
58
|
+
if (arch !== "x64") return false
|
|
59
|
+
|
|
60
|
+
if (platform === "linux") {
|
|
61
|
+
try {
|
|
62
|
+
return /(^|\s)avx2(\s|$)/i.test(fs.readFileSync("/proc/cpuinfo", "utf8"))
|
|
63
|
+
} catch {
|
|
64
|
+
return false
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
if (platform === "darwin") {
|
|
69
|
+
try {
|
|
70
|
+
const result = childProcess.spawnSync("sysctl", ["-n", "hw.optional.avx2_0"], {
|
|
71
|
+
encoding: "utf8",
|
|
72
|
+
timeout: 1500,
|
|
73
|
+
})
|
|
74
|
+
if (result.status !== 0) return false
|
|
75
|
+
return (result.stdout || "").trim() === "1"
|
|
76
|
+
} catch {
|
|
77
|
+
return false
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
if (platform === "windows") {
|
|
82
|
+
const cmd =
|
|
83
|
+
'(Add-Type -MemberDefinition "[DllImport(""kernel32.dll"")] public static extern bool IsProcessorFeaturePresent(int ProcessorFeature);" -Name Kernel32 -Namespace Win32 -PassThru)::IsProcessorFeaturePresent(40)'
|
|
84
|
+
|
|
85
|
+
for (const exe of ["powershell.exe", "pwsh.exe", "pwsh", "powershell"]) {
|
|
86
|
+
try {
|
|
87
|
+
const result = childProcess.spawnSync(exe, ["-NoProfile", "-NonInteractive", "-Command", cmd], {
|
|
88
|
+
encoding: "utf8",
|
|
89
|
+
timeout: 3000,
|
|
90
|
+
windowsHide: true,
|
|
91
|
+
})
|
|
92
|
+
if (result.status !== 0) continue
|
|
93
|
+
const out = (result.stdout || "").trim().toLowerCase()
|
|
94
|
+
if (out === "true" || out === "1") return true
|
|
95
|
+
if (out === "false" || out === "0") return false
|
|
96
|
+
} catch {
|
|
97
|
+
continue
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
return false
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
return false
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
const names = (() => {
|
|
108
|
+
const avx2 = supportsAvx2()
|
|
109
|
+
const baseline = arch === "x64" && !avx2
|
|
110
|
+
|
|
111
|
+
if (platform === "linux") {
|
|
112
|
+
const musl = (() => {
|
|
113
|
+
try {
|
|
114
|
+
if (fs.existsSync("/etc/alpine-release")) return true
|
|
115
|
+
} catch {
|
|
116
|
+
// ignore
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
try {
|
|
120
|
+
const result = childProcess.spawnSync("ldd", ["--version"], { encoding: "utf8" })
|
|
121
|
+
const text = ((result.stdout || "") + (result.stderr || "")).toLowerCase()
|
|
122
|
+
if (text.includes("musl")) return true
|
|
123
|
+
} catch {
|
|
124
|
+
// ignore
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
return false
|
|
128
|
+
})()
|
|
129
|
+
|
|
130
|
+
if (musl) {
|
|
131
|
+
if (arch === "x64") {
|
|
132
|
+
if (baseline) return [`${base}-baseline-musl`, `${base}-musl`, `${base}-baseline`, base]
|
|
133
|
+
return [`${base}-musl`, `${base}-baseline-musl`, base, `${base}-baseline`]
|
|
134
|
+
}
|
|
135
|
+
return [`${base}-musl`, base]
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
if (arch === "x64") {
|
|
139
|
+
if (baseline) return [`${base}-baseline`, base, `${base}-baseline-musl`, `${base}-musl`]
|
|
140
|
+
return [base, `${base}-baseline`, `${base}-musl`, `${base}-baseline-musl`]
|
|
141
|
+
}
|
|
142
|
+
return [base, `${base}-musl`]
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
if (arch === "x64") {
|
|
146
|
+
if (baseline) return [`${base}-baseline`, base]
|
|
147
|
+
return [base, `${base}-baseline`]
|
|
148
|
+
}
|
|
149
|
+
return [base]
|
|
150
|
+
})()
|
|
151
|
+
|
|
152
|
+
function findBinary(startDir) {
|
|
153
|
+
let current = startDir
|
|
154
|
+
for (;;) {
|
|
155
|
+
const modules = path.join(current, "node_modules")
|
|
156
|
+
if (fs.existsSync(modules)) {
|
|
157
|
+
for (const name of names) {
|
|
158
|
+
const candidate = path.join(modules, scope, name, "bin", binary)
|
|
159
|
+
if (fs.existsSync(candidate)) return candidate
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
const parent = path.dirname(current)
|
|
163
|
+
if (parent === current) {
|
|
164
|
+
return
|
|
165
|
+
}
|
|
166
|
+
current = parent
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
const resolved = findBinary(scriptDir)
|
|
171
|
+
if (!resolved) {
|
|
172
|
+
console.error(
|
|
173
|
+
"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 " +
|
|
174
|
+
names.map((n) => `\"${scope}/${n}\"`).join(" or ") +
|
|
175
|
+
" package",
|
|
176
|
+
)
|
|
177
|
+
process.exit(1)
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
run(resolved)
|
|
@@ -0,0 +1,180 @@
|
|
|
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
|
+
function run(target) {
|
|
9
|
+
const result = childProcess.spawnSync(target, process.argv.slice(2), {
|
|
10
|
+
stdio: "inherit",
|
|
11
|
+
})
|
|
12
|
+
if (result.error) {
|
|
13
|
+
console.error(result.error.message)
|
|
14
|
+
process.exit(1)
|
|
15
|
+
}
|
|
16
|
+
const code = typeof result.status === "number" ? result.status : 0
|
|
17
|
+
process.exit(code)
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
const envPath = process.env.ALTIMATE_CODE_BIN_PATH
|
|
21
|
+
if (envPath) {
|
|
22
|
+
run(envPath)
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
const scriptPath = fs.realpathSync(__filename)
|
|
26
|
+
const scriptDir = path.dirname(scriptPath)
|
|
27
|
+
|
|
28
|
+
//
|
|
29
|
+
const cached = path.join(scriptDir, ".altimate-code")
|
|
30
|
+
if (fs.existsSync(cached)) {
|
|
31
|
+
run(cached)
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
const platformMap = {
|
|
35
|
+
darwin: "darwin",
|
|
36
|
+
linux: "linux",
|
|
37
|
+
win32: "windows",
|
|
38
|
+
}
|
|
39
|
+
const archMap = {
|
|
40
|
+
x64: "x64",
|
|
41
|
+
arm64: "arm64",
|
|
42
|
+
arm: "arm",
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
let platform = platformMap[os.platform()]
|
|
46
|
+
if (!platform) {
|
|
47
|
+
platform = os.platform()
|
|
48
|
+
}
|
|
49
|
+
let arch = archMap[os.arch()]
|
|
50
|
+
if (!arch) {
|
|
51
|
+
arch = os.arch()
|
|
52
|
+
}
|
|
53
|
+
const scope = "@altimateai"
|
|
54
|
+
const base = "altimate-code-" + platform + "-" + arch
|
|
55
|
+
const binary = platform === "windows" ? "altimate-code.exe" : "altimate-code"
|
|
56
|
+
|
|
57
|
+
function supportsAvx2() {
|
|
58
|
+
if (arch !== "x64") return false
|
|
59
|
+
|
|
60
|
+
if (platform === "linux") {
|
|
61
|
+
try {
|
|
62
|
+
return /(^|\s)avx2(\s|$)/i.test(fs.readFileSync("/proc/cpuinfo", "utf8"))
|
|
63
|
+
} catch {
|
|
64
|
+
return false
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
if (platform === "darwin") {
|
|
69
|
+
try {
|
|
70
|
+
const result = childProcess.spawnSync("sysctl", ["-n", "hw.optional.avx2_0"], {
|
|
71
|
+
encoding: "utf8",
|
|
72
|
+
timeout: 1500,
|
|
73
|
+
})
|
|
74
|
+
if (result.status !== 0) return false
|
|
75
|
+
return (result.stdout || "").trim() === "1"
|
|
76
|
+
} catch {
|
|
77
|
+
return false
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
if (platform === "windows") {
|
|
82
|
+
const cmd =
|
|
83
|
+
'(Add-Type -MemberDefinition "[DllImport(""kernel32.dll"")] public static extern bool IsProcessorFeaturePresent(int ProcessorFeature);" -Name Kernel32 -Namespace Win32 -PassThru)::IsProcessorFeaturePresent(40)'
|
|
84
|
+
|
|
85
|
+
for (const exe of ["powershell.exe", "pwsh.exe", "pwsh", "powershell"]) {
|
|
86
|
+
try {
|
|
87
|
+
const result = childProcess.spawnSync(exe, ["-NoProfile", "-NonInteractive", "-Command", cmd], {
|
|
88
|
+
encoding: "utf8",
|
|
89
|
+
timeout: 3000,
|
|
90
|
+
windowsHide: true,
|
|
91
|
+
})
|
|
92
|
+
if (result.status !== 0) continue
|
|
93
|
+
const out = (result.stdout || "").trim().toLowerCase()
|
|
94
|
+
if (out === "true" || out === "1") return true
|
|
95
|
+
if (out === "false" || out === "0") return false
|
|
96
|
+
} catch {
|
|
97
|
+
continue
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
return false
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
return false
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
const names = (() => {
|
|
108
|
+
const avx2 = supportsAvx2()
|
|
109
|
+
const baseline = arch === "x64" && !avx2
|
|
110
|
+
|
|
111
|
+
if (platform === "linux") {
|
|
112
|
+
const musl = (() => {
|
|
113
|
+
try {
|
|
114
|
+
if (fs.existsSync("/etc/alpine-release")) return true
|
|
115
|
+
} catch {
|
|
116
|
+
// ignore
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
try {
|
|
120
|
+
const result = childProcess.spawnSync("ldd", ["--version"], { encoding: "utf8" })
|
|
121
|
+
const text = ((result.stdout || "") + (result.stderr || "")).toLowerCase()
|
|
122
|
+
if (text.includes("musl")) return true
|
|
123
|
+
} catch {
|
|
124
|
+
// ignore
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
return false
|
|
128
|
+
})()
|
|
129
|
+
|
|
130
|
+
if (musl) {
|
|
131
|
+
if (arch === "x64") {
|
|
132
|
+
if (baseline) return [`${base}-baseline-musl`, `${base}-musl`, `${base}-baseline`, base]
|
|
133
|
+
return [`${base}-musl`, `${base}-baseline-musl`, base, `${base}-baseline`]
|
|
134
|
+
}
|
|
135
|
+
return [`${base}-musl`, base]
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
if (arch === "x64") {
|
|
139
|
+
if (baseline) return [`${base}-baseline`, base, `${base}-baseline-musl`, `${base}-musl`]
|
|
140
|
+
return [base, `${base}-baseline`, `${base}-musl`, `${base}-baseline-musl`]
|
|
141
|
+
}
|
|
142
|
+
return [base, `${base}-musl`]
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
if (arch === "x64") {
|
|
146
|
+
if (baseline) return [`${base}-baseline`, base]
|
|
147
|
+
return [base, `${base}-baseline`]
|
|
148
|
+
}
|
|
149
|
+
return [base]
|
|
150
|
+
})()
|
|
151
|
+
|
|
152
|
+
function findBinary(startDir) {
|
|
153
|
+
let current = startDir
|
|
154
|
+
for (;;) {
|
|
155
|
+
const modules = path.join(current, "node_modules")
|
|
156
|
+
if (fs.existsSync(modules)) {
|
|
157
|
+
for (const name of names) {
|
|
158
|
+
const candidate = path.join(modules, scope, name, "bin", binary)
|
|
159
|
+
if (fs.existsSync(candidate)) return candidate
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
const parent = path.dirname(current)
|
|
163
|
+
if (parent === current) {
|
|
164
|
+
return
|
|
165
|
+
}
|
|
166
|
+
current = parent
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
const resolved = findBinary(scriptDir)
|
|
171
|
+
if (!resolved) {
|
|
172
|
+
console.error(
|
|
173
|
+
"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 " +
|
|
174
|
+
names.map((n) => `\"${scope}/${n}\"`).join(" or ") +
|
|
175
|
+
" package",
|
|
176
|
+
)
|
|
177
|
+
process.exit(1)
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
run(resolved)
|
package/package.json
CHANGED
|
@@ -1,10 +1,33 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "altimate-code",
|
|
3
|
-
"
|
|
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.7",
|
|
18
|
+
"license": "MIT",
|
|
19
|
+
"optionalDependencies": {
|
|
20
|
+
"@altimateai/altimate-code-linux-x64": "v0.4.7",
|
|
21
|
+
"@altimateai/altimate-code-windows-arm64": "v0.4.7",
|
|
22
|
+
"@altimateai/altimate-code-linux-arm64-musl": "v0.4.7",
|
|
23
|
+
"@altimateai/altimate-code-darwin-x64": "v0.4.7",
|
|
24
|
+
"@altimateai/altimate-code-windows-x64": "v0.4.7",
|
|
25
|
+
"@altimateai/altimate-code-linux-x64-musl": "v0.4.7",
|
|
26
|
+
"@altimateai/altimate-code-darwin-x64-baseline": "v0.4.7",
|
|
27
|
+
"@altimateai/altimate-code-linux-x64-baseline-musl": "v0.4.7",
|
|
28
|
+
"@altimateai/altimate-code-linux-x64-baseline": "v0.4.7",
|
|
29
|
+
"@altimateai/altimate-code-linux-arm64": "v0.4.7",
|
|
30
|
+
"@altimateai/altimate-code-darwin-arm64": "v0.4.7",
|
|
31
|
+
"@altimateai/altimate-code-windows-x64-baseline": "v0.4.7"
|
|
9
32
|
}
|
|
10
|
-
}
|
|
33
|
+
}
|
package/postinstall.mjs
ADDED
|
@@ -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
|
+
}
|