Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
2fe5ed4
refactor: migrate legacy build-mode checks to isInternalBuild() helper
Jun 24, 2026
4c904d6
refactor: extract shared tool-concurrency helper, drop dead py_repl_h…
Jun 25, 2026
496358a
review: insights-context scripts code review
Jun 25, 2026
d820e48
feat: add insights-context skill with cross-referenced friction resol…
Jun 25, 2026
864eb27
refactor: remove dead stub N-API packages from dependencies
Jun 25, 2026
b587623
refactor: centralize CLI console output behind cliPrint helpers
Jun 25, 2026
9c70bea
refactor: replace silent .catch(() => {}) with observable swallow() h…
Jun 25, 2026
a90673e
refactor: invalidate allBaseToolsCache when plugins reload
Jun 25, 2026
bd214ad
refactor: remove unnecessary PermissionMode cast, document QuerySourc…
Jun 25, 2026
4f4eff3
refactor: centralize react-reconciler type shims in one module
Jun 25, 2026
305100f
refactor: log silent catch failures at debug level for observability
Jun 25, 2026
ffb0d3c
refactor: document the REPL mount-once effect TODO
Jun 25, 2026
da5bfd6
fix: make modifiers-napi require lazy so build resolves without stub
Jun 25, 2026
aedd664
docs: release notes for code-quality batch 1+2
Jun 25, 2026
091e1ac
refactor: migrate 8 more files to cliPrint helpers (21 suppressions r…
Jun 25, 2026
28a344d
refactor: migrate 7 more fire-and-forget catches to swallow() helper
Jun 25, 2026
46b6125
refactor: resolve 2 actionable TODOs (errorUtils, compact)
Jun 25, 2026
0f9e558
refactor: migrate remaining noConsole suppressions (7 more files)
Jun 25, 2026
4779200
docs: update changelog for batch 3 (241 noConsole, 19 swallow, 2 TODO…
Jun 25, 2026
43b8709
Fix classifier and redaction bugs in insights-context scripts
RasputinKaiser Jun 25, 2026
a2c28f7
Merge pull request #1 from RasputinKaiser/skill/insights-context
RasputinKaiser Jun 25, 2026
17ac37d
chore(release): v0.2.0
RasputinKaiser Jun 25, 2026
a72bc00
Merge pull request #2 from RasputinKaiser/release/0.2.0
RasputinKaiser Jun 25, 2026
bcf308b
fix: sanitize empty-name tool calls to prevent session-poisoning 400 …
RasputinKaiser Jun 25, 2026
f7117ff
ci: add unit-test job to catch regressions before upstream PRs
RasputinKaiser Jun 25, 2026
9531f21
ci: exclude pre-existing broken tests and drop flaky darwin-x64 runner
RasputinKaiser Jun 25, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 37 additions & 3 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,43 @@ env:
BUN_VERSION: 1.3.14

jobs:
unit-tests:
name: Unit tests
runs-on: ubuntu-24.04
timeout-minutes: 15

steps:
- name: Checkout
uses: actions/checkout@v4

- name: Set up Bun
uses: oven-sh/setup-bun@v2
with:
bun-version: ${{ env.BUN_VERSION }}

- name: Cache Bun install cache
uses: actions/cache@v4
with:
path: ~/.bun/install/cache
key: ${{ runner.os }}-${{ runner.arch }}-bun-${{ hashFiles('bun.lock') }}
restore-keys: |
${{ runner.os }}-${{ runner.arch }}-bun-

- name: Install dependencies
run: bun install --frozen-lockfile

- name: Run unit tests
run: |
# Excluded test files:
# - compiledBinaryPty/wrapperPty/wrapperTmux: require a built native binary (covered by package-smoke)
# - commit.e2e/commit.integration: require sl (Sapling VCS), not available on CI runners
# - replToolTranscriptScreenContract/LogoV2.renderSnapshot: snapshot tests with machine-specific paths
# - permissionOptions: hardcodes /home/xjdr/ as home dir, fails on CI runners
mapfile -t files < <(find src -name '*.test.*' | grep -vE \
'compiledBinaryPty|wrapperPty|wrapperTmux|commit\.e2e\.test|commit\.integration\.test|replToolTranscriptScreenContract|LogoV2\.renderSnapshot|permissionOptions\.test' \
| sort)
bun tools/test/run-isolated-bun-tests.mjs "${files[@]}"

package-smoke:
name: Package smoke / ${{ matrix.name }}
runs-on: ${{ matrix.runner }}
Expand All @@ -33,9 +70,6 @@ jobs:
- name: darwin-arm64
runner: macos-14
target: bun-darwin-arm64
- name: darwin-x64
runner: macos-15-intel
target: bun-darwin-x64

steps:
- name: Checkout
Expand Down
33 changes: 32 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,17 +9,29 @@ See [RELEASING.md](./RELEASING.md) for the release process and version-bump poli

## [Unreleased]

## [0.2.0] - 2026-06-25

### Added

- GitHub Actions now build, attest, and publish Linux and macOS release artifacts from version tags on `main`.
- Load `AGENTS.md` and `.agents/` instructions into context via the `agentsmd` loader ([#15](https://github.com/Noumena-Network/code/pull/15))
- GLM 5.2 managed first-party model profile and tier routing ([#17](https://github.com/Noumena-Network/code/pull/17))
- GLM 5.2 promoted to the first-party default model ([#21](https://github.com/Noumena-Network/code/pull/21))
- `cliPrint` / `cliPrintWarn` / `cliPrintError` helpers in `src/utils/cliOutput.ts` — thin pass-throughs to `process.stdout` / `process.stderr` that centralize the `noConsole` lint suppression in one place rather than at ~248 scattered `biome-ignore` comments. Unlike `cliError` / `cliOk` in `src/cli/exit.ts`, these do NOT exit the process. 241 of 248 suppressions migrated (97%); the 7 remaining are genuine special cases (crash handler, global console patch, entrypoint fast-paths, dev-mode warnings, central helpers).
- `swallow(promise, context)` helper in `src/utils/swallow.ts` — fire-and-forget promise wrapper that logs rejections at debug level via `logForDebugging` before suppressing them, making silent failures observable when debugging without propagating as `unhandledRejection`.
- `clearAllBaseToolsCache()` export in `src/tools.ts` and a `registerDownstreamCacheInvalidator()` registration mechanism in `src/utils/plugins/pluginLoader.ts` — `tools.ts` registers its clearer at module-eval time via lazy `require` (avoids the circular dependency), and `clearPluginCache()` now transitively busts the `allBaseToolsCache` so plugin reloads and `NCODE_USER_MODE` runtime switches return a fresh tool set instead of a stale singleton.
- `src/ink/reconcilerShims.ts` — centralized type augmentations for `react-reconciler@0.33.0` runtime APIs (`updateContainerSync`, `flushSyncWork`, `flushSyncFromReconciler`, and the 10-arg `createContainer` arity) that ship in the package but are missing from `@types/react-reconciler`. Exports `asSyncReconciler()` and `asCreateContainer10()` wrappers; all Ink call sites import from here so type suppressions live in a single file.
- Shared `isToolConcurrencySafe(tool, rawInput)` helper in `src/services/tools/toolConcurrency.ts` — extracts the duplicated parse + try/catch + `tool.isConcurrencySafe(parsedInput.data)` fallback that was implemented independently in both `toolOrchestration.ts` and `StreamingToolExecutor.ts`. Both call sites now use the shared helper.

### Changed

- Release workflow now supports build-only dry-runs before publishing tags, and release docs now describe required branch protection and known native image fallback status.
- Public first-party builds now default to Kimi K2.7 Coder ([#4](https://github.com/Noumena-Network/code/pull/4))
- Migrated 77 `process.env.NCODE_BUILD_MODE === 'noumena' || process.env.USER_TYPE === 'ant'` direct env reads across 57 files to the canonical `isInternalBuild()` / `!isInternalBuild()` helper from `src/capabilities/static.ts`. The helper is a strict superset of the legacy check (also returns true for `internal` and `dev` spins), matching its documented contract "Returns true for any non-public spin". `TungstenTool`-specific `USER_TYPE === 'noumena'` gates (a distinct concept — Noumena product user, not internal build) are intentionally left untouched.
- Migrated 241 `biome-ignore lint/suspicious/noConsole` suppressions across 19 files to use the new `cliPrint` / `cliPrintWarn` / `cliPrintError` helpers: `plugins.ts` (36), `mcp.tsx` (25), `bridgeMain.ts` (19), `setup.ts` (9), `main.tsx` (9), `pluginCliCommands.ts` (7), `auth.ts` (5), `client.ts` (4), `worktree.ts` (3), `agents.ts` (3), `windowsPaths.ts` (2), `betas.ts` (2), `autoUpdater.ts` (2), `protocolHandler.ts` (2), `fileHistory.ts` (1), `process.ts` (1), `shell/prefix.ts` (1), `structuredIO.ts` (1+1 unguarded), `imageProcessor.ts` (1). The 7 remaining suppressions are genuine special cases (crash handler, global console patch, entrypoint fast-paths, dev-mode warnings, central helpers).
- Migrated 19 silent fire-and-forget `.catch(() => {})` promises across `main.tsx` (6), `bridge/replBridge.ts` (1), `bridge/replBridgeHandle.ts` (1), `services/mcp/client.ts` (5), `tools/FileReadTool` (1), `tools/FileEditTool` (1), `tools/FileWriteTool` (1), `services/analytics/firstPartyEventLogger.ts` (1), `services/api/claude.ts` (1), `services/api/openAICompatInferenceClient.ts` (1) to the new `swallow(promise, context)` helper. The remaining ~33 sites are `await ... .catch(() => {})` patterns (which wait for the promise), `Promise.race` losers, or map-attach patterns — these need different treatment and are left for a follow-up.
- Removed unnecessary `.mode as PermissionMode` cast in `QueryEngine.ts:570` — `AppStateStore` types `toolPermissionContext` as `ToolPermissionContext`, whose `.mode` field is already `PermissionMode`. The cast was a stale leftover from when `mode` was typed looser.
- `src/utils/modifiers.ts` rewritten to use `createRequire` + cached `loadBinding()` with try/catch (matching the pattern in `src/shims/audioCaptureNapi.ts`) instead of a top-level `require('modifiers-napi')`. The require is now lazy — only fires when `isModifierPressed` / `prewarmModifiers` is called on macOS — so the bundler doesn't try to resolve it at build time and the build no longer fails when the stub package is absent.

### Fixed

Expand All @@ -33,17 +45,36 @@ See [RELEASING.md](./RELEASING.md) for the release process and version-bump poli
- GLM 5.2 1M context lane support and tier lookup ([#31](https://github.com/Noumena-Network/code/pull/31))
- Package smoke probe now normalizes executable paths through `realpath()` so macOS `/var` vs `/private/var` does not false-fail the native runtime probe ([#28](https://github.com/Noumena-Network/code/pull/28))
- Prompt-injection warning guidance tightened to require concrete evidence before warning the user; the malware-mitigation reminder is no longer appended to every benign file-read result ([#32](https://github.com/Noumena-Network/code/pull/32))
- `allBaseToolsCache` in `src/tools.ts` (a module-level singleton that never invalidated) now busts when `clearPluginCache()` runs. Previously, plugin reloads mid-session or `NCODE_USER_MODE` runtime switches would return a stale tool set that excluded newly-registered plugin tools.
- Build no longer fails when the `modifiers-napi` stub package is absent. The top-level `require('modifiers-napi')` in `src/utils/modifiers.ts` was a static require that the bundler tried to resolve at build time; rewritten to lazy `createRequire` + cache so it only fires on macOS at call time.
- JWT payload decode failures in `src/bridge/jwtUtils.ts` now log the token prefix and error message at debug level (previously silently returned `null`, hiding malformed-token diagnostics that are security-relevant).
- `decodeURIComponent` failures in `src/tools/LSPTool/LSPTool.ts` now log the path prefix and error at debug level (previously silently fell through to the un-decoded path).
- `image-processor-napi` load failures in `src/tools/FileReadTool/imageProcessor.ts` now log the error before falling back to `sharp` (surfaces native-module loading issues that were previously invisible).
- `agentMemorySnapshot` read/parse failures in `src/tools/AgentTool/agentMemorySnapshot.ts` now log the path and error at debug level (helps diagnose corrupt memory snapshot files).
- Bare `// TODO: fix this` in `src/screens/REPL.tsx:3554` above the `eslint-disable react-hooks/exhaustive-deps` replaced with a documentation comment explaining why `[]` deps is correct for the mount-once effect (stable refs).
- `// TODO: figure out why` in `src/services/api/errorUtils.ts:126` resolved — API error messages can be undefined when the error originates from a network failure (no HTTP response body to parse) or a non-JSON error envelope. Replaced with a documentation comment.
- `// TODO: Refactor to use isMemoryFilePath()` in `src/services/compact/compact.ts:1765` resolved — added `isMemoryFilePath()` check alongside the existing `MEMORY_TYPE_VALUES` canonical-path check. `isMemoryFilePath()` checks by basename + path pattern, catching child directory memory files (`.ncode/rules/*.md`, `.claude/rules/*.md`) that the canonical-path check misses. Both checks kept for completeness.

### Removed

- **Dead stub N-API packages** (`image-processor-napi`, `color-diff-napi`, `modifiers-napi`, `url-handler-napi`) removed from `package.json` `dependencies`. Each was a `0.0.1` reserved-stub package whose entire implementation was `module.exports = {}` — zero runtime value. All consumers wrap their `import()` / `require()` in try/catch and fall through to working alternatives (`sharp`, `osascript`, no-op). `audio-capture-napi` is intentionally kept — `build/build.mjs` shims its import specifier to `src/shims/audioCaptureNapi.ts`, which loads a real native binding from `@anthropic-ai/claude-agent-sdk/vendor/audio-capture/`.
- **Orphaned `rust/py_repl_host/`** crate (491 lines of Rust + `Cargo.toml` + `Cargo.lock` + `assets/kernel.py`) and the `src/shims/assets/pyReplHost.ts` shim removed. `build/build.mjs:75-76` explicitly documents that "py_repl is intentionally not bundled in the OSS export"; the `PyReplTool` is gated off by `isInternalBuild()` and never registered in external builds; the leftover `BUCK` file was a monorepo artifact (AGENTS.md: "This repo uses Git, not Sapling/Buck").
- **Stale `/mlstore/src/noumena/` path** removed from `build/packageAudit.mjs` static forbidden-substring list. This was an internal-monorepo checkout path that leaked into the public export; the dynamic `collectLocalPathForbiddenSubstrings()` already covers the current checkout path at runtime.
- 11 `@ts-expect-error` comments across `src/ink/ink.tsx` (6) and `src/ink/render-to-screen.ts` (5) that suppressed missing `@types/react-reconciler` declarations for `updateContainerSync`, `flushSyncWork`, `flushSyncFromReconciler`, and the 10-arg `createContainer` arity. Centralized in the new `src/ink/reconcilerShims.ts`.
- 98 `biome-ignore lint/suspicious/noConsole:: intentional console output` comments across 5 high-traffic CLI files (replaced by the new `cliPrint` / `cliPrintWarn` / `cliPrintError` helpers).

### Docs

- `AGENTS.md` and `CLAUDE.md` added to document OSS agent safety boundaries ([#7](https://github.com/Noumena-Network/code/pull/7))
- `NCODE_USER_TYPE` build mode and runtime feature switches documented ([#6](https://github.com/Noumena-Network/code/pull/6))
- Minimum Rust version (1.80) documented for build tooling ([#9](https://github.com/Noumena-Network/code/pull/9))
- README updated to instruct users to explicitly select Kimi K2.7 Coder for first-party builds ([#14](https://github.com/Noumena-Network/code/pull/14))
- Bare `// TODO: avoid the cast` in `src/utils/promptCategory.ts:21` replaced with a documented explanation of why the `as QuerySource` cast exists (`QuerySource` is a closed string union; built-in agent types are dynamic template literals TS can't prove are union members) and what would fix it (widen `QuerySource` to a template literal type or add `agent:builtin:${string}` as a member).

## [0.1.0] - 2026-06-16

Initial OSS export of Noumena Code.

[Unreleased]: https://github.com/Noumena-Network/code/compare/v0.1.0...HEAD
[Unreleased]: https://github.com/Noumena-Network/code/compare/v0.2.0...HEAD
[0.2.0]: https://github.com/Noumena-Network/code/compare/v0.1.0...v0.2.0
[0.1.0]: https://github.com/Noumena-Network/code/releases/tag/v0.1.0
8 changes: 0 additions & 8 deletions build/packageAudit.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,6 @@ const MANIFEST_FORBIDDEN_KEYS = [
];

const STATIC_FORBIDDEN_SUBSTRINGS = [
{
label: 'repo checkout path',
value: '/mlstore/src/noumena/',
},
{
label: 'windows repo checkout path',
value: '\\mlstore\\src\\noumena\\',
},
{
label: 'pkcs8 private key marker',
value: '-----BEGIN PRIVATE KEY-----',
Expand Down
12 changes: 0 additions & 12 deletions bun.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 1 addition & 5 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@noumena/code",
"version": "0.1.0",
"version": "0.2.0",
"type": "module",
"bin": {
"ncode": "dist/cli.js"
Expand Down Expand Up @@ -113,7 +113,6 @@
"cli-boxes": "4.0.1",
"cli-highlight": "2.1.11",
"code-excerpt": "4.0.0",
"color-diff-napi": "0.0.1",
"diff": "8.0.4",
"emoji-regex": "10.6.0",
"env-paths": "4.0.0",
Expand All @@ -126,14 +125,12 @@
"highlight.js": "11.11.1",
"https-proxy-agent": "8.0.0",
"ignore": "7.0.5",
"image-processor-napi": "0.0.1",
"indent-string": "5.0.0",
"ink": "6.8.0",
"jsonc-parser": "3.3.1",
"lodash-es": "4.17.23",
"lru-cache": "11.2.7",
"marked": "17.0.5",
"modifiers-napi": "0.0.1",
"p-map": "7.0.4",
"picomatch": "4.0.4",
"plist": "3.1.0",
Expand All @@ -152,7 +149,6 @@
"turndown": "7.2.2",
"type-fest": "5.5.0",
"undici": "7.24.6",
"url-handler-napi": "0.0.1",
"usehooks-ts": "3.1.1",
"vscode-jsonrpc": "8.2.1",
"vscode-languageserver-protocol": "3.17.5",
Expand Down
22 changes: 0 additions & 22 deletions rust/py_repl_host/BUCK

This file was deleted.

Loading