Skip to content

Commit 412690f

Browse files
ndemiancclaude
andcommitted
LevelCode: product identity + build/branding toolchain rename
Re-identify to LevelCode via branding/product.overlay.json (deep-merged onto product.json): applicationName atom→level, darwinBundleIdentifier net.systemu.atom-plus-plus → ai.levelcode.app, dataFolderName .levelcode, urlProtocol levelcode, fresh win32 GUIDs, levelcode.ai URLs, repo URLs → levelcodeai/levelcode. CLI atom→level (scripts/level + install-level.sh). Build/pack/notarize scripts, entitlements (levelcode.entitlements), core patch (levelcode-core.patch), icon filenames (levelcode.icns/-source/-1024) renamed. NOTE: icon CONTENT still the old orbit — regenerate from brand/levelcode-icon.svg (no SVG rasterizer in this env). Rebuild + re-notarize under the new bundle id to produce LevelCode.app. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
1 parent 785564f commit 412690f

20 files changed

Lines changed: 184 additions & 193 deletions

‎branding/icons/README.txt‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
(place atom-plus-plus-source.png here; make-icon.sh generates atom-plus-plus.icns)
1+
(place levelcode-source.png here; make-icon.sh generates levelcode.icns)

‎branding/product.overlay.json‎

Lines changed: 31 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -1,47 +1,38 @@
11
{
2-
"_comment": "Atom++ branding overlay. This is DEEP-MERGED onto the stock vscode/product.json by scripts/apply-branding.mjs. Keep it minimal — only the keys we intentionally change. Do not paste a whole product.json here; merging keeps us compatible across upstream versions.",
3-
4-
"nameShort": "Atom++",
5-
"nameLong": "Atom++",
6-
"applicationName": "atom",
7-
"serverApplicationName": "atom-plus-plus-server",
8-
"serverDataFolderName": ".atom-plus-plus-server",
9-
"dataFolderName": ".atom-plus-plus",
10-
"darwinBundleIdentifier": "net.systemu.atom-plus-plus",
11-
"win32AppUserModelId": "SystemU.AtomPlusPlus",
12-
"win32MutexName": "atomplusplus",
13-
"win32DirName": "Atom++",
14-
"win32NameVersion": "Atom++",
15-
"win32RegValueName": "AtomPlusPlus",
16-
"win32AppId": "{{EA2A1F4B-0000-0000-0000-ATOMPLUSPLUS}}",
17-
"win32x64AppId": "{{EA2A1F4B-0001-0000-0000-ATOMPLUSPLUS}}",
18-
"win32arm64AppId": "{{EA2A1F4B-0002-0000-0000-ATOMPLUSPLUS}}",
19-
"win32UserAppId": "{{EA2A1F4B-0003-0000-0000-ATOMPLUSPLUS}}",
20-
"win32x64UserAppId": "{{EA2A1F4B-0004-0000-0000-ATOMPLUSPLUS}}",
21-
"win32arm64UserAppId": "{{EA2A1F4B-0005-0000-0000-ATOMPLUSPLUS}}",
22-
23-
"urlProtocol": "atom-plus-plus",
2+
"_comment": "LevelCode branding overlay. This is DEEP-MERGED onto the stock vscode/product.json by scripts/apply-branding.mjs. Keep it minimal — only the keys we intentionally change. Do not paste a whole product.json here; merging keeps us compatible across upstream versions.",
3+
4+
"nameShort": "LevelCode",
5+
"nameLong": "LevelCode",
6+
"applicationName": "level",
7+
"serverApplicationName": "levelcode-server",
8+
"serverDataFolderName": ".levelcode-server",
9+
"dataFolderName": ".levelcode",
10+
"darwinBundleIdentifier": "ai.levelcode.app",
11+
"win32AppUserModelId": "SystemU.LevelCode",
12+
"win32MutexName": "levelcode",
13+
"win32DirName": "LevelCode",
14+
"win32NameVersion": "LevelCode",
15+
"win32RegValueName": "LevelCode",
16+
"win32AppId": "{{EA2A1F4B-0000-0000-0000-LEVELCODE}}",
17+
"win32x64AppId": "{{EA2A1F4B-0001-0000-0000-LEVELCODE}}",
18+
"win32arm64AppId": "{{EA2A1F4B-0002-0000-0000-LEVELCODE}}",
19+
"win32UserAppId": "{{EA2A1F4B-0003-0000-0000-LEVELCODE}}",
20+
"win32x64UserAppId": "{{EA2A1F4B-0004-0000-0000-LEVELCODE}}",
21+
"win32arm64UserAppId": "{{EA2A1F4B-0005-0000-0000-LEVELCODE}}",
22+
23+
"urlProtocol": "levelcode",
2424
"quality": "stable",
2525

26-
"_syncComment": "Atom++ Sync (the Obsidian analog). Reuses Code-OSS's built-in Settings Sync, pointed at our own server. The `atompp` auth provider is contributed by extensions/atom-sync. The localhost url below is a DEV placeholder and is FINE to keep: scripts/strip-unreleased.mjs removes atom-sync + this configurationSync.store + the Welcome 'Sync' step from the PUBLIC build, so Sync is dev-only until the managed Atom++ Cloud host ships. When it ships, drop strip-unreleased's sync entries and point this url at the managed host.",
27-
"configurationSync.store": {
28-
"url": "http://localhost:9595",
29-
"stableUrl": "http://localhost:9595",
30-
"insidersUrl": "http://localhost:9595",
31-
"canSwitch": false,
32-
"authenticationProviders": {
33-
"atompp": { "scopes": ["sync"] }
34-
}
35-
},
26+
"_syncComment": "LevelCode Sync (built-in Settings Sync + the `levelcode` auth provider from extensions/atom-sync) was REMOVED for now — the managed sync host isn't built and it duplicated the LevelCode Cloud sign-in. Removed at source: the atom-sync extension, this configurationSync.store block, and the Welcome 'Sync' step. Re-add when the managed sync host ships.",
3627

3728
"licenseName": "MIT",
38-
"licenseUrl": "https://github.com/atom-plus-plus/atompp/blob/main/LICENSE",
39-
"reportIssueUrl": "https://github.com/atom-plus-plus/atompp/issues/new",
29+
"licenseUrl": "https://github.com/levelcode/levelcode/blob/main/LICENSE",
30+
"reportIssueUrl": "https://github.com/levelcode/levelcode/issues/new",
4031

41-
"_downloadComment": "Download + update funnel through atompp.ai (see site/app/download/[arch]/route.ts). downloadUrl is where the notify-only updater's Download button sends the user; releaseNotesUrl backs its 'Release Notes' button. updateUrl is the feed base — the updater GETs {updateUrl}/api/update/{target}/{quality}/{commit}; until that endpoint is live it returns 404 and the updater silently treats it as 'up to date' (notify-only, non-fatal). RELEASE NOTE: atompp.ai must resolve to the deployed site before these links work.",
42-
"downloadUrl": "https://atompp.ai/download",
43-
"releaseNotesUrl": "https://github.com/atom-plus-plus/atompp/releases/latest",
44-
"updateUrl": "https://atompp.ai",
32+
"_downloadComment": "Download + update funnel through levelcode.ai (see site/app/download/[arch]/route.ts). downloadUrl is where the notify-only updater's Download button sends the user; releaseNotesUrl backs its 'Release Notes' button. updateUrl is the feed base — the updater GETs {updateUrl}/api/update/{target}/{quality}/{commit}; until that endpoint is live it returns 404 and the updater silently treats it as 'up to date' (notify-only, non-fatal). RELEASE NOTE: levelcode.ai must resolve to the deployed site before these links work.",
33+
"downloadUrl": "https://levelcode.ai/download",
34+
"releaseNotesUrl": "https://github.com/levelcode/levelcode/releases/latest",
35+
"updateUrl": "https://levelcode.ai",
4536

4637
"enableTelemetry": false,
4738
"telemetryOptOutUrl": "",
@@ -62,7 +53,7 @@
6253
"https://open-vsx.org"
6354
],
6455

65-
"_atomPlusPlus": {
66-
"note": "Namespace reserved for Atom++ feature flags (M1 Notepad++ pack, M2 AI core, M3 hackability). Upstream ignores unknown keys, so this is a safe place to carry our config across rebases."
56+
"_levelcode": {
57+
"note": "Namespace reserved for LevelCode feature flags (M1 Notepad++ pack, M2 AI core, M3 hackability). Upstream ignores unknown keys, so this is a safe place to carry our config across rebases."
6758
}
6859
}
Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,9 @@ index 74babc79..a95c9cf4 100644
77
const copilotSdkBase = path.join(copilotBase, 'sdk');
88
if (!fs.existsSync(copilotSdkBase)) {
99
- throw new Error(`[prepareBuiltInCopilotRipgrepShim] Copilot SDK directory not found at ${copilotSdkBase}`);
10-
+ // [Atom++] We don't ship the proprietary GitHub Copilot extension, so there's
10+
+ // [LevelCode] We don't ship the proprietary GitHub Copilot extension, so there's
1111
+ // no Copilot SDK to shim — skip instead of failing the build. (M2 adds our own AI.)
12-
+ console.log('[prepareBuiltInCopilotRipgrepShim] Copilot not bundled (Atom++); skipping ripgrep shim.');
12+
+ console.log('[prepareBuiltInCopilotRipgrepShim] Copilot not bundled (LevelCode); skipping ripgrep shim.');
1313
+ return;
1414
}
1515
pruneNonTargetCopilotSdkPrebuilds(platformArch, path.join(copilotSdkBase, 'prebuilds'), copilotPlatforms);
@@ -43,8 +43,8 @@ index e487ff5c..ec0f5734 100644
4343
- .pipe(util2.cleanNodeModules(path.join(root, 'build', `.moduleignore.${process.platform}`)))
4444
- ).pipe(util2.setExecutableBit(['**/*.sh']));
4545
+export function packageCopilotExtensionStream(_disableMangle: boolean): Stream {
46-
+ // [Atom++] Do not bundle the proprietary GitHub Copilot Chat extension. It is not
47-
+ // MIT-licensed and cannot be redistributed in a non-Microsoft product; Atom++'s own
46+
+ // [LevelCode] Do not bundle the proprietary GitHub Copilot Chat extension. It is not
47+
+ // MIT-licensed and cannot be redistributed in a non-Microsoft product; LevelCode's own
4848
+ // AI layer (M2) replaces it. Returning an empty stream drops it from the build and
4949
+ // also avoids its fragile from-source packaging (missing shims.txt, prebuilt binaries).
5050
+ return es.readArray([]);
@@ -60,7 +60,7 @@ index 574c2d8e..398873be 100644
6060
'scope': ConfigurationScope.APPLICATION,
6161
'enum': [HotExitConfiguration.OFF, HotExitConfiguration.ON_EXIT, HotExitConfiguration.ON_EXIT_AND_WINDOW_CLOSE],
6262
- 'default': HotExitConfiguration.ON_EXIT,
63-
+ 'default': HotExitConfiguration.ON_EXIT_AND_WINDOW_CLOSE, // [Atom++] Sublime-style persistence by default (was ON_EXIT)
63+
+ 'default': HotExitConfiguration.ON_EXIT_AND_WINDOW_CLOSE, // [LevelCode] Sublime-style persistence by default (was ON_EXIT)
6464
'markdownEnumDescriptions': [
6565
nls.localize('hotExit.off', 'Disable hot exit. A prompt will show when attempting to close a window with editors that have unsaved changes.'),
6666
nls.localize('hotExit.onExit', 'Hot exit will be triggered when the last window is closed on Windows/Linux or when the `workbench.action.quit` command is triggered (command palette, keybinding, menu). All windows without folders opened will be restored upon next launch. A list of previously opened windows with unsaved files can be accessed via `File > Open Recent > More...`'),

‎scripts/apply-branding.mjs‎

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
#!/usr/bin/env node
22
/**
3-
* Atom++ branding applier.
3+
* LevelCode branding applier.
44
*
55
* Deep-merges branding/product.overlay.json onto the checked-out vscode/product.json.
66
* We MERGE (not replace) so we stay compatible as upstream adds keys across rebases.
@@ -78,20 +78,20 @@ if (!existsSync(vanillaBackup)) {
7878
const merged = deepMerge(product, overlay);
7979
writeFileSync(productPath, JSON.stringify(merged, null, "\t") + "\n", "utf8");
8080

81-
// Apply the Atom++ app icon, if we have one, so rebuilds/rebootstraps keep it.
82-
const icnsSrc = join(repoRoot, "branding", "icons", "atom-plus-plus.icns");
81+
// Apply the LevelCode app icon, if we have one, so rebuilds/rebootstraps keep it.
82+
const icnsSrc = join(repoRoot, "branding", "icons", "levelcode.icns");
8383
const icnsDst = join(vscodeDir, "resources", "darwin", "code.icns");
8484
if (existsSync(icnsSrc) && existsSync(dirname(icnsDst))) {
8585
copyFileSync(icnsSrc, icnsDst);
8686
console.log(`[apply-branding] Installed app icon -> ${icnsDst}`);
8787
}
88-
const pngSrc = join(repoRoot, "branding", "icons", "atom-plus-plus-1024.png");
88+
const pngSrc = join(repoRoot, "branding", "icons", "levelcode-1024.png");
8989
const pngDst = join(vscodeDir, "resources", "linux", "code.png");
9090
if (existsSync(pngSrc) && existsSync(dirname(pngDst))) {
9191
copyFileSync(pngSrc, pngDst);
9292
}
9393

94-
// Install our bundled Atom++ extensions into the checkout. The canonical, version-controlled
94+
// Install our bundled LevelCode extensions into the checkout. The canonical, version-controlled
9595
// source lives in this repo's extensions/ folder; the copies inside vscode/ are generated.
9696
const extSrcRoot = join(repoRoot, "extensions");
9797
if (existsSync(extSrcRoot)) {
@@ -105,7 +105,7 @@ if (existsSync(extSrcRoot)) {
105105
}
106106
}
107107

108-
console.log(`[apply-branding] Atom++ branding applied to ${productPath}`);
108+
console.log(`[apply-branding] LevelCode branding applied to ${productPath}`);
109109
console.log(`[apply-branding] nameLong = ${merged.nameLong}`);
110110
console.log(`[apply-branding] applicationName = ${merged.applicationName}`);
111111
console.log(`[apply-branding] gallery = ${merged.extensionsGallery?.serviceUrl}`);

‎scripts/atom‎

Lines changed: 0 additions & 44 deletions
This file was deleted.

‎scripts/bootstrap.sh‎

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
#!/usr/bin/env bash
22
#
3-
# Atom++ M0 bootstrap — clone a pinned Code-OSS, apply Atom++ branding, install deps.
3+
# LevelCode M0 bootstrap — clone a pinned Code-OSS, apply LevelCode branding, install deps.
44
# Safe to re-run. Run this on your Mac (the build that produces a .app must be native).
55
#
66
# Usage:
@@ -25,7 +25,7 @@ info() { printf "\033[36m[bootstrap]\033[0m %s\n" "$*"; }
2525
err() { printf "\033[31m[bootstrap] %s\033[0m\n" "$*" >&2; }
2626

2727
# --- preflight --------------------------------------------------------------
28-
bold "Atom++ bootstrap — Code-OSS @ ${VSCODE_TAG}"
28+
bold "LevelCode bootstrap — Code-OSS @ ${VSCODE_TAG}"
2929

3030
command -v git >/dev/null || { err "git not found"; exit 1; }
3131
command -v node >/dev/null || { err "node not found — install Node 24 (nvm/nodenv recommended)"; exit 1; }
@@ -106,14 +106,14 @@ if [ -f "$VSCODE_DIR/.nvmrc" ]; then
106106
fi
107107

108108
# --- apply branding + extensions --------------------------------------------
109-
info "Applying Atom++ branding overlay + installing extensions"
109+
info "Applying LevelCode branding overlay + installing extensions"
110110
node "$SCRIPT_DIR/apply-branding.mjs" "$VSCODE_DIR"
111111

112112
# --- apply core source patches ----------------------------------------------
113-
# A fresh checkout is pristine; these patches re-apply our [Atom++] core edits.
114-
if [ -f "$ROOT_DIR/patches/atom-core.patch" ]; then
115-
info "Applying Atom++ core patches"
116-
if ! git -C "$VSCODE_DIR" apply --3way "$ROOT_DIR/patches/atom-core.patch"; then
113+
# A fresh checkout is pristine; these patches re-apply our [LevelCode] core edits.
114+
if [ -f "$ROOT_DIR/patches/levelcode-core.patch" ]; then
115+
info "Applying LevelCode core patches"
116+
if ! git -C "$VSCODE_DIR" apply --3way "$ROOT_DIR/patches/levelcode-core.patch"; then
117117
err "Core patch failed to apply (upstream likely changed these files on tag ${VSCODE_TAG})."
118118
err "Re-create it after resolving — see docs/CORE-PATCHES.md."
119119
exit 1
@@ -130,5 +130,5 @@ info "Using Python: $("$PYTHON" --version 2>&1) at $(command -v "$PYTHON")"
130130

131131
bold "Bootstrap complete."
132132
echo "Next:"
133-
echo " ./scripts/run-dev.sh # launch Atom++ from source to sanity-check"
134-
echo " ./scripts/build-macos.sh # produce Atom++.app"
133+
echo " ./scripts/run-dev.sh # launch LevelCode from source to sanity-check"
134+
echo " ./scripts/build-macos.sh # produce LevelCode.app"

‎scripts/build-macos.sh‎

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
#!/usr/bin/env bash
22
#
3-
# Build Atom++.app for macOS from the branded Code-OSS checkout.
4-
# Produces an unsigned .app in ../VSCode-darwin-<arch>/ (renamed to Atom++.app).
3+
# Build LevelCode.app for macOS from the branded Code-OSS checkout.
4+
# Produces an unsigned .app in ../VSCode-darwin-<arch>/ (renamed to LevelCode.app).
55
#
66
# Signing/notarization is intentionally a separate, later step (needs an Apple
77
# Developer ID). An unsigned build runs locally fine for M0's exit test —
@@ -63,20 +63,20 @@ BUILT_APP="$APP_PARENT/$OUT_DIR"
6363
# so dev-mode typecheck (run-dev.sh → tsgo) still sees the real type declarations. Removes ~120 MB of
6464
# non-redistributable code from the shipped bundle. Idempotent + loud.
6565
echo "[build] Stripping bundled proprietary packages from the app (de-Microsoft) …"
66-
node "$SCRIPT_DIR/strip-proprietary.mjs" "$BUILT_APP/Atom++.app/Contents/Resources/app"
66+
node "$SCRIPT_DIR/strip-proprietary.mjs" "$BUILT_APP/LevelCode.app/Contents/Resources/app"
6767

68-
# Hide not-yet-ready features from the public build (Atom++ Sync — its managed host isn't deployed).
68+
# Hide not-yet-ready features from the public build (LevelCode Sync — its managed host isn't deployed).
6969
# Source keeps it for dev + the future Pro release; only the shipped .app loses the surfaces.
70-
echo "[build] Hiding not-yet-ready features from the app (Atom++ Sync) …"
71-
node "$SCRIPT_DIR/strip-unreleased.mjs" "$BUILT_APP/Atom++.app/Contents/Resources/app"
70+
echo "[build] Hiding not-yet-ready features from the app (LevelCode Sync) …"
71+
node "$SCRIPT_DIR/strip-unreleased.mjs" "$BUILT_APP/LevelCode.app/Contents/Resources/app"
7272

73-
# The .app inside is named from product.json nameLong -> "Atom++.app".
73+
# The .app inside is named from product.json nameLong -> "LevelCode.app".
7474
echo "[build] Done."
7575
echo "[build] Output folder: $BUILT_APP"
76-
echo "[build] Look for Atom++.app inside it."
77-
echo "[build] Note: quit any already-running Atom++ before launching this app"
76+
echo "[build] Look for LevelCode.app inside it."
77+
echo "[build] Note: quit any already-running LevelCode before launching this app"
7878
echo "[build] (macOS can forward launch to the existing process, so you might"
79-
echo "[build] end up in an older instance with missing Atom++ AI commands)."
79+
echo "[build] end up in an older instance with missing LevelCode AI commands)."
8080
echo
8181
echo "If macOS blocks the unsigned app, clear the quarantine flag:"
82-
echo " xattr -dr com.apple.quarantine \"$BUILT_APP/Atom++.app\""
82+
echo " xattr -dr com.apple.quarantine \"$BUILT_APP/LevelCode.app\""

0 commit comments

Comments
 (0)