Skip to content

Loader and bootstrap workflows

This file explains how execution reaches app.js and what app.js does before entering the main command/runtime flow.

Relevant files:

  • copilot-cli-pkg/npm-loader.js
  • copilot-cli-pkg/sea-loader.js
  • copilot-cli-pkg/index.js
  • copilot-cli-pkg/app.js

At runtime, sea-loader.js and the embedded copilot.tgz live inside the native copilot binary. The extractor now preserves the recovered sea-loader.js beside the expanded package for analysis; the archive itself is retained only when the extractor is run with --keep-package-tgz.

This page opens the Runtime lifecycle chapter. It explains how execution reaches app.js before command parsing, sessions, context assembly, or tools exist. Continue to Mode dispatch and runtime startup for root command dispatch, then to Sessions, persistence, and remote once a runtime mode owns a session.

Source anchors

app.js is bundled and minified, so the semantic aliases below are documentation names. Loader filenames are stable package anchors, while minified anchors are version-specific lookup aids.

Semantic aliasMinified anchorLocationRole
npm launchercopilot-cli-pkg/npm-loader.jspackage binResolves and spawns the installed native platform package, or prints a reinstall error when none is available.
SEA loadercopilot-cli-pkg/sea-loader.jsnative SEA mainSelects/extracts a cached package version and imports its index.js.
JavaScript restart wrappercopilot-cli-pkg/index.js, COPILOT_RUN_APP, restart code 75package loaderSelects active package version, spawns child runtime, forwards signals, and restarts on update handoff.
App bootstrap modulecopilot-cli-pkg/app.jsbundle entryInstalls restricted module loading, Git safety config, and runtime services before CLI dispatch.
Restricted require shimcreateRequire, app-path containment checkearly app.js bootstrapAllows Node built-ins and approved vendored native modules while rejecting resolved paths outside the app directory.
OOP native require root__napiOopEntrypoint, napi-oop-runtimeapp.js ~15-63Resolves the Node transport used when native runtime calls are remoted to a Rust parent.
Git hardeningLVe(), safe.bareRepository=explicit, GIT_CONFIG_COUNTearly app.js bootstrapAdds environment-backed Git safety configuration.
Config migrationCOPILOT_HOME, XDG .copilot migration helpersearly app.js bootstrapResolves state/config roots and compatibility migration behavior.

Distribution layout

The extracted binary is a Node/V8 single executable application (SEA) that carries a loader and a tarball asset. The tarball expands into the @github/copilot package.

flowchart TD
Binary["Native copilot executable"] --> SEA["Node SEA payload"]
SEA --> SeaLoader["sea-loader.js"]
SEA --> PackageArchive["copilot.tgz asset"]
PackageArchive --> Package["expanded @github/copilot package"]
Package --> NpmLoader["npm-loader.js"]
Package --> Index["index.js"]
Package --> App["app.js"]
Package --> Metadata["package.json"]
Metadata --> Version["@github/copilot"]
Metadata --> Bin["bin: copilot -> npm-loader.js"]

npm/native launcher path

When installed as an npm package, the copilot bin points at npm-loader.js. In the current package, that loader resolves and spawns the matching platform-native package. If no platform package is installed, it prints a reinstall error; it does not run app.js directly.

flowchart TD
Start["user runs copilot"] --> NpmLoader["npm-loader.js"]
NpmLoader --> NativeCheck{"platform package exists?"}
NativeCheck -- yes --> NativePkg["@github/copilot-platform-arch"]
NativePkg --> SpawnNative["spawn native binary with same args"]
SpawnNative --> NativeRuntime["native SEA runtime"]
NativeCheck -- no --> Fail["print reinstall/platform-package error"]
NativeRuntime --> SeaLoader["embedded sea-loader.js"]
SeaLoader --> IndexRuntime["selected package index.js"]
IndexRuntime --> App["app.js"]

index.js update/restart wrapper

The JavaScript loader wrapper does more than import app.js. It chooses the active package version, supports auto-update cache locations, spawns a child process with COPILOT_RUN_APP=1, forwards signals, and handles restart exit code 75.

flowchart TD
IndexStart["index.js starts"] --> EnvCheck{"COPILOT_RUN_APP == 1?"}
EnvCheck -- yes --> SelectApp["select preferred app.js"]
SelectApp --> ImportApp["dynamic import app.js"]
EnvCheck -- no --> AutoUpdateCheck{"auto-update enabled?"}
AutoUpdateCheck -- yes --> FindCached["find cached/copied package versions"]
AutoUpdateCheck -- no --> UseBundled["use bundled package"]
FindCached --> ChooseVersion["choose preferred version"]
UseBundled --> ChooseVersion
ChooseVersion --> SpawnChild["spawn child with COPILOT_RUN_APP=1"]
SpawnChild --> ForwardSignals["forward process signals"]
SpawnChild --> ExitCode{"child exit code"}
ExitCode -- normal --> ExitSame["exit with child code"]
ExitCode -- 75 --> RestartFile["read restart resume JSON"]
RestartFile --> SpawnChild

Early app.js bootstrap

The beginning of app.js sets up ESM/CommonJS compatibility and a restricted require shim. It allows built-in Node modules and selected vendored native modules, but rejects resolved module paths outside the application directory.

flowchart TD
AppStart["app.js module evaluation"] --> Imports["import node:module/path/fs/url"]
Imports --> RootRequire["create __rootRequire"]
RootRequire --> AppPath["realpath of application directory"]
AppPath --> NativeRoots["create require roots for vendored native modules"]
NativeRoots --> RequireShim["define custom require(module)"]
RequireShim --> ModuleType{"requested module"}
ModuleType -- "approved vendored native" --> NativeRequire["load via vendored native require"]
ModuleType -- "Node builtin" --> BuiltinRequire["load builtin"]
ModuleType -- "regular package" --> ResolvePath["resolve module path"]
ResolvePath --> InsideCheck{"inside app path?"}
InsideCheck -- yes --> AppRequire["load module"]
InsideCheck -- no --> SecurityError["throw security error"]

Approved vendored-native module families observed in the bootstrap section include:

  • sharp
  • clipboard
  • foundry-local-sdk
  • @picovoice/pvrecorder-node
  • napi-oop-runtime
  • scoped native dependencies such as @img/* and @teddyzhu/*

napi-oop-runtime has its own package-local createRequire root. See Out-of-process native runtime bridge for the mode switch, connect-back protocol, manifest binding, callbacks, and handle lifetime.

Git safety hardening

Early in startup, app.js adds safe.bareRepository=explicit to Git’s environment-backed config list. This constrains how Git treats bare repositories during CLI operations.

flowchart TD
GitSetup["LVe() git setup"] --> ReadCount["read GIT_CONFIG_COUNT"]
ReadCount --> AlreadySet{"safe.bareRepository already present?"}
AlreadySet -- yes --> Done["leave environment unchanged"]
AlreadySet -- no --> AppendKey["append GIT_CONFIG_KEY_N=safe.bareRepository"]
AppendKey --> AppendValue["append GIT_CONFIG_VALUE_N=explicit"]
AppendValue --> Increment["increment GIT_CONFIG_COUNT"]

Config and state directory migration

The runtime recognizes COPILOT_HOME and XDG locations. The observed XDG migration helper moves selected state/config files from XDG-based .copilot locations back to the default home location when appropriate, then creates compatibility symlinks.

flowchart TD
MigrationStart["startup config migration"] --> EnvVars["check XDG_STATE_HOME and XDG_CONFIG_HOME"]
EnvVars --> ExistingXdg{"XDG .copilot exists and differs from ~/.copilot?"}
ExistingXdg -- no --> Skip["skip migration"]
ExistingXdg -- yes --> EnsureHome["ensure ~/.copilot exists"]
EnsureHome --> ForEachItem["for selected state/config items"]
ForEachItem --> TargetExists{"target already exists?"}
TargetExists -- yes --> WarnSkip["warn and skip item"]
TargetExists -- no --> MoveItem["move or copy item"]
MoveItem --> LinkBack["create symlink back to XDG path"]

Bootstrap summary

Before the user-facing CLI logic runs, app.js has already:

  • constrained dynamic module loading;
  • installed Git safety config in environment variables;
  • checked Node compatibility;
  • prepared config/state directory behavior;
  • defined shutdown/error/logging infrastructure used later by the top-level action.

Created and maintained by Yingting Huang.