affaan-m/ECC · error · Error

TypeScript compiler not found. Install root dev dependencies

Error message

TypeScript compiler not found. Install root dev dependencies before publishing so .opencode/dist can be built.

What it means

_validate_file_path() blocks any resolved path that falls under OS system directories (/etc, /usr, /bin, /sbin, /proc, /sys, /var/log, /var/run, /var/lib, /var/spool, plus macOS /private/etc, /private/var/log, /private/var/run, /private/var/db). This is a system-safety / path-traversal guard that fires even when the path is valid and exists, because writing instinct storage into system dirs could corrupt the OS or exfiltrate data. The check runs after .resolve() so symlinks are followed.

Source

Thrown at scripts/build-opencode.js:18

#!/usr/bin/env node

const fs = require("node:fs")
const path = require("node:path")
const { execFileSync } = require("node:child_process")

const rootDir = path.resolve(__dirname, "..")
const opencodeDir = path.join(rootDir, ".opencode")
const distDir = path.join(opencodeDir, "dist")

fs.rmSync(distDir, { recursive: true, force: true })

let tscEntrypoint

try {
  tscEntrypoint = require.resolve("typescript/bin/tsc", { paths: [rootDir] })
} catch {
  throw new Error(
    "TypeScript compiler not found. Install root dev dependencies before publishing so .opencode/dist can be built."
  )
}

execFileSync(process.execPath, [tscEntrypoint, "-p", path.join(opencodeDir, "tsconfig.json")], {
  cwd: rootDir,
  stdio: "inherit",
})

View on GitHub (pinned to 01e15490f0)

Solutions

  1. Point the path at a project-local or user-data directory (e.g. under the project root or ~/.local/share).
  2. Remove or avoid symlinks inside the working tree that resolve into /etc, /usr, /var, etc.
  3. If you genuinely need a system path, copy the relevant file into a non-system location first and validate that.

Example fix

# before
_validate_file_path('/etc/myapp/instinct.md')  # blocked

# after
_validate_file_path(project_root / 'instincts' / 'myapp.md')
Defensive patterns

Strategy: validation

Validate before calling

# Pre-check against the same blocked prefixes before calling.
import os
BLOCKED = ('/etc', '/usr', '/bin', '/sbin', '/proc', '/sys',
           '/var/log', '/var/run', '/var/lib', '/var/spool',
           '/private/etc', '/private/var/log', '/private/var/run', '/private/var/db')
resolved = str(os.path.realpath(path))
for prefix in BLOCKED:
    if resolved == prefix or resolved.startswith(prefix + '/'):
        raise SystemExit(f'refusing to use system path {resolved}')

Type guard

import os

def is_safe_user_path(p) -> bool:
    resolved = str(os.path.realpath(p))
    blocked = ('/etc', '/usr', '/bin', '/sbin', '/proc', '/sys',
               '/var/log', '/var/run', '/var/lib', '/var/spool')
    return not any(resolved == b or resolved.startswith(b + '/') for b in blocked)

Try / catch

try:
    _validate_file_path(user_path)
except ValueError as e:
    if 'system directory' in str(e):
        log.error('rejected system path: %s', user_path)
    raise

Prevention

When it happens

Trigger: Passing '/etc/myconfig'; a symlink inside the project that resolves to /usr/local/...; an expanduser('~') that on a misconfigured system lands under a blocked prefix; a user-supplied path containing '../etc'.

Common situations: A project contains a symlink pointing into a system directory; a path was constructed from untrusted input without sanitization; the home directory was misconfigured to resolve under /var.

Related errors


AI-assisted analysis of affaan-m/ECC@01e15490f0 (2026-08-13). Data as JSON: /api/errors/6414405b16596ca2. Report an issue: GitHub.