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
- Point the path at a project-local or user-data directory (e.g. under the project root or ~/.local/share).
- Remove or avoid symlinks inside the working tree that resolve into /etc, /usr, /var, etc.
- 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
- Keep instinct storage under the project root or a designated user-data directory.
- Avoid symlinks inside the working tree that point into system directories.
- Sanitize all user-supplied paths at the trust boundary, not deep in the call stack.
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
- ${source} is missing the expected catalog marker
- ${EXECUTABLE_OVERRIDE} does not point to a readable local It
- Refusing to read non-file path: ${filePath}
- ${label} must be a regular, non-symlink file.
- seedPaths entries must stay inside repoRoot: ${entry}
AI-assisted analysis of affaan-m/ECC@01e15490f0 (2026-08-13).
Data as JSON: /api/errors/6414405b16596ca2.
Report an issue: GitHub.