impel-cli 0.17.2 → 0.17.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +15 -0
- package/package.json +1 -1
- package/src/apps.js +42 -12
package/README.md
CHANGED
|
@@ -311,3 +311,18 @@ run a real package manager, or modify native personal profiles.
|
|
|
311
311
|
|
|
312
312
|
CI runs on Ubuntu, macOS, and Windows with supported Node versions. See
|
|
313
313
|
[RELEASING.md](RELEASING.md) for the npm release process.
|
|
314
|
+
|
|
315
|
+
The macOS config-contract job downloads the exact ChatGPT archive declared in
|
|
316
|
+
`PINNED_VENDOR_APPS`, verifies its checksum, signature, app version, and
|
|
317
|
+
embedded Codex version, then validates a deterministic generated profile with
|
|
318
|
+
Codex's strict config loader. A ChatGPT pin update must also update the embedded
|
|
319
|
+
Codex version and the reviewed config fixture when its contract changes.
|
|
320
|
+
|
|
321
|
+
The pinned Claude contract job likewise force-downloads the exact desktop app,
|
|
322
|
+
verifies the embedded Claude Code release manifest, builds the managed bundle
|
|
323
|
+
with ad-hoc signing, and checks deterministic generated desktop and Claude Code
|
|
324
|
+
settings against a reviewed fixture. The manifest-selected Claude Code runtime
|
|
325
|
+
runs `doctor` in bare mode against an isolated profile; CI intercepts the
|
|
326
|
+
`security` command so the check cannot read, reset, unlock, or modify a
|
|
327
|
+
Keychain. A Claude pin update must also update its `claudeCodeVersion` and
|
|
328
|
+
`claudeCodeCommit` pins and reviewed contract fixture.
|
package/package.json
CHANGED
package/src/apps.js
CHANGED
|
@@ -43,6 +43,8 @@ const APP_DEFINITIONS = {
|
|
|
43
43
|
export const PINNED_VENDOR_APPS = Object.freeze({
|
|
44
44
|
claude: Object.freeze({
|
|
45
45
|
version: "1.20186.9",
|
|
46
|
+
claudeCodeVersion: "2.1.209",
|
|
47
|
+
claudeCodeCommit: "0fe048596fd45e79e99353cbe2c3d1b1ac069568",
|
|
46
48
|
bundleName: "Claude.app",
|
|
47
49
|
downloads: Object.freeze({
|
|
48
50
|
arm64: Object.freeze({
|
|
@@ -57,6 +59,7 @@ export const PINNED_VENDOR_APPS = Object.freeze({
|
|
|
57
59
|
}),
|
|
58
60
|
chatgpt: Object.freeze({
|
|
59
61
|
version: "26.707.72221",
|
|
62
|
+
codexVersion: "0.144.2",
|
|
60
63
|
bundleName: "ChatGPT.app",
|
|
61
64
|
downloads: Object.freeze({
|
|
62
65
|
arm64: Object.freeze({
|
|
@@ -589,6 +592,7 @@ export function installManagedAppFiles({
|
|
|
589
592
|
writeTokenHelperFile = true,
|
|
590
593
|
claudeUserData = null,
|
|
591
594
|
chatgptInvocations = null,
|
|
595
|
+
generatedAt = new Date().toISOString(),
|
|
592
596
|
}) {
|
|
593
597
|
// true = rebuild every target's bundle; false = configs only; an array
|
|
594
598
|
// limits the expensive rebuild to just the stale targets.
|
|
@@ -621,7 +625,14 @@ export function installManagedAppFiles({
|
|
|
621
625
|
ensureClaudeSessionHooks(paths.claude.userData, config.tenantId, "claude_desktop");
|
|
622
626
|
}
|
|
623
627
|
else {
|
|
624
|
-
writeChatGPTConfig(
|
|
628
|
+
writeChatGPTConfig(
|
|
629
|
+
paths,
|
|
630
|
+
config,
|
|
631
|
+
models,
|
|
632
|
+
vendorCodexModels,
|
|
633
|
+
chatgptInvocations,
|
|
634
|
+
generatedAt,
|
|
635
|
+
);
|
|
625
636
|
ensureCodexSessionHooks(paths.chatgpt.codexHome, config.tenantId, "codex_desktop");
|
|
626
637
|
}
|
|
627
638
|
// Non-bundle targets are the background-refresh / fast-open path: configs,
|
|
@@ -666,7 +677,7 @@ export function installManagedAppFiles({
|
|
|
666
677
|
config,
|
|
667
678
|
),
|
|
668
679
|
models: models.map((model) => model.id),
|
|
669
|
-
updatedAt:
|
|
680
|
+
updatedAt: generatedAt,
|
|
670
681
|
}, null, 2) + "\n", 0o600);
|
|
671
682
|
return installed;
|
|
672
683
|
}
|
|
@@ -815,10 +826,13 @@ function installPinnedVendorApp(target, homeDir) {
|
|
|
815
826
|
}
|
|
816
827
|
}
|
|
817
828
|
|
|
818
|
-
export function ensureVendorApp(target, {
|
|
829
|
+
export function ensureVendorApp(target, {
|
|
830
|
+
homeDir = os.homedir(),
|
|
831
|
+
forceDownload = false,
|
|
832
|
+
} = {}) {
|
|
819
833
|
const definition = APP_DEFINITIONS[target];
|
|
820
834
|
const pin = PINNED_VENDOR_APPS[target];
|
|
821
|
-
const current = findVendorApp(target, homeDir);
|
|
835
|
+
const current = forceDownload ? null : findVendorApp(target, homeDir);
|
|
822
836
|
if (current) return { path: current, action: "existing", note: `verified ${pin.version}` };
|
|
823
837
|
|
|
824
838
|
// Name-collision transparency: e.g. OpenAI's native ChatGPT chat app
|
|
@@ -974,7 +988,14 @@ function writeClaudeDefaultApp(paths) {
|
|
|
974
988
|
writeAtomic(configPath, JSON.stringify(next, null, 2) + "\n", 0o600);
|
|
975
989
|
}
|
|
976
990
|
|
|
977
|
-
function writeChatGPTConfig(
|
|
991
|
+
function writeChatGPTConfig(
|
|
992
|
+
paths,
|
|
993
|
+
config,
|
|
994
|
+
models,
|
|
995
|
+
vendorCodexModels,
|
|
996
|
+
invocations = null,
|
|
997
|
+
generatedAt = new Date().toISOString(),
|
|
998
|
+
) {
|
|
978
999
|
const experimental = crossAppModelsEnabled(config);
|
|
979
1000
|
const orderedModels = experimental
|
|
980
1001
|
? [...models.filter((model) => model.provider === "codex"), ...models.filter((model) => model.provider === "claude")]
|
|
@@ -1008,7 +1029,7 @@ function writeChatGPTConfig(paths, config, models, vendorCodexModels, invocation
|
|
|
1008
1029
|
? configuredTier
|
|
1009
1030
|
: (configuredTier === "fast" && supportedTiers.includes("priority") ? "priority" : null);
|
|
1010
1031
|
const catalog = {
|
|
1011
|
-
fetched_at:
|
|
1032
|
+
fetched_at: generatedAt,
|
|
1012
1033
|
client_version: "impel-managed-2",
|
|
1013
1034
|
models: codexModels,
|
|
1014
1035
|
};
|
|
@@ -1209,18 +1230,27 @@ function codexCatalogEntry(model, index, vendorModel) {
|
|
|
1209
1230
|
function readVendorCodexModels(vendorPath) {
|
|
1210
1231
|
const binary = vendorPath && path.join(vendorPath, "Contents", "Resources", "codex");
|
|
1211
1232
|
if (!binary || !fs.existsSync(binary)) return new Map();
|
|
1212
|
-
const
|
|
1213
|
-
|
|
1214
|
-
|
|
1215
|
-
|
|
1216
|
-
|
|
1233
|
+
const codexHome = fs.mkdtempSync(path.join(os.tmpdir(), "impel-vendor-codex-models-"));
|
|
1234
|
+
try {
|
|
1235
|
+
// Vendor enrichment must come only from the exact bundled release. Reading
|
|
1236
|
+
// the operator's native CODEX_HOME here would make generated app configs
|
|
1237
|
+
// depend on unrelated local state and could trigger an online catalog read.
|
|
1238
|
+
const env = { ...process.env, CODEX_HOME: codexHome };
|
|
1239
|
+
const result = spawnSync(binary, ["debug", "models", "--bundled"], {
|
|
1240
|
+
encoding: "utf8",
|
|
1241
|
+
env,
|
|
1242
|
+
maxBuffer: 20 * 1024 * 1024,
|
|
1243
|
+
});
|
|
1244
|
+
if (result.status !== 0) return new Map();
|
|
1217
1245
|
try {
|
|
1218
1246
|
const payload = JSON.parse(result.stdout);
|
|
1219
1247
|
const models = Array.isArray(payload) ? payload : payload.models;
|
|
1220
1248
|
if (Array.isArray(models)) return new Map(models.map((model) => [model.slug, model]));
|
|
1221
1249
|
} catch {
|
|
1222
|
-
// Fall through to the
|
|
1250
|
+
// Fall through to the Impel-generated schema.
|
|
1223
1251
|
}
|
|
1252
|
+
} finally {
|
|
1253
|
+
fs.rmSync(codexHome, { recursive: true, force: true });
|
|
1224
1254
|
}
|
|
1225
1255
|
return new Map();
|
|
1226
1256
|
}
|