impel-cli 0.20.54 → 0.20.55
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/RELEASE_NOTES.md +12 -0
- package/package.json +1 -1
- package/src/managedApps.js +106 -18
package/RELEASE_NOTES.md
CHANGED
|
@@ -1,5 +1,17 @@
|
|
|
1
1
|
# Release notes
|
|
2
2
|
|
|
3
|
+
## 0.20.55 — Route managed CLIs through the signed runner
|
|
4
|
+
|
|
5
|
+
- Launches `impel codex` and `impel claude` through the tenant-agnostic macOS
|
|
6
|
+
managed runner when the corresponding signed descriptor is installed.
|
|
7
|
+
- Binds each launch to the exact logical application ID and leaves descriptor
|
|
8
|
+
signature, trust-anchor, runtime-lock, and payload verification with the
|
|
9
|
+
signed runner before any vendor CLI starts.
|
|
10
|
+
- Prefers the standalone Codex MSI on Windows while retaining the legacy
|
|
11
|
+
ChatGPT-embedded Codex package only as a compatibility fallback.
|
|
12
|
+
- Stops newly managed Codex sessions from reaching retired macOS wrappers that
|
|
13
|
+
injected an invalid `--console` argument into no-argument launches.
|
|
14
|
+
|
|
3
15
|
## 0.20.54 — Restore ChatGPT Store compatibility and scope skills per tenant
|
|
4
16
|
|
|
5
17
|
- Restores managed ChatGPT/Codex installation on Windows by pinning Store
|
package/package.json
CHANGED
package/src/managedApps.js
CHANGED
|
@@ -4,7 +4,12 @@ import path from "node:path";
|
|
|
4
4
|
import { spawn } from "node:child_process";
|
|
5
5
|
|
|
6
6
|
const TENANT = /^[a-z0-9](?:[a-z0-9._-]{0,62}[a-z0-9])?$/u;
|
|
7
|
-
const
|
|
7
|
+
const APPLICATIONS_BY_TOOL = Object.freeze({
|
|
8
|
+
claude: ["claude"],
|
|
9
|
+
codex: ["codex", "chatgpt"],
|
|
10
|
+
});
|
|
11
|
+
const MAC_RUNNER = "/Applications/Impel Managed App Runner.app/Contents/Library/LaunchServices/impel-managed-runner";
|
|
12
|
+
const MAC_DESCRIPTOR_ROOT = "/Library/Application Support/Impel/Managed App Runner/descriptors";
|
|
8
13
|
|
|
9
14
|
function regularFile(file) {
|
|
10
15
|
try {
|
|
@@ -15,7 +20,7 @@ function regularFile(file) {
|
|
|
15
20
|
}
|
|
16
21
|
}
|
|
17
22
|
|
|
18
|
-
function parseCandidate(manifestPath, launcher,
|
|
23
|
+
function parseCandidate(manifestPath, launcher, applicationId, platform, home) {
|
|
19
24
|
if (!regularFile(manifestPath) || !regularFile(launcher)) return null;
|
|
20
25
|
let manifest;
|
|
21
26
|
try {
|
|
@@ -25,7 +30,6 @@ function parseCandidate(manifestPath, launcher, tool, platform, home) {
|
|
|
25
30
|
} catch {
|
|
26
31
|
return null;
|
|
27
32
|
}
|
|
28
|
-
const applicationId = APPLICATION_BY_TOOL[tool];
|
|
29
33
|
const tenantId = manifest?.tenant?.id;
|
|
30
34
|
const expectedPlatform = platform === "win32" ? "windows" : "macos";
|
|
31
35
|
if (
|
|
@@ -46,11 +50,12 @@ function parseCandidate(manifestPath, launcher, tool, platform, home) {
|
|
|
46
50
|
tenantId,
|
|
47
51
|
tenantDisplayName: typeof manifest.tenant.displayName === "string" ? manifest.tenant.displayName : tenantId,
|
|
48
52
|
launcher,
|
|
53
|
+
logicalApplicationId: manifest.logicalApplicationId,
|
|
49
54
|
manifestPath,
|
|
50
55
|
};
|
|
51
56
|
}
|
|
52
57
|
|
|
53
|
-
function
|
|
58
|
+
function legacyMacCandidates(tool, home, applicationsRoot) {
|
|
54
59
|
let entries;
|
|
55
60
|
try {
|
|
56
61
|
entries = fs.readdirSync(applicationsRoot, { withFileTypes: true });
|
|
@@ -58,13 +63,14 @@ function macCandidates(tool, home, applicationsRoot) {
|
|
|
58
63
|
return [];
|
|
59
64
|
}
|
|
60
65
|
const candidates = [];
|
|
66
|
+
const applicationId = tool === "codex" ? "chatgpt" : tool;
|
|
61
67
|
for (const entry of entries) {
|
|
62
68
|
if (!entry.isDirectory() || !entry.name.endsWith(".app")) continue;
|
|
63
69
|
const root = path.join(applicationsRoot, entry.name, "Contents");
|
|
64
70
|
const candidate = parseCandidate(
|
|
65
71
|
path.join(root, "Resources", "app-manifest.json"),
|
|
66
72
|
path.join(root, "MacOS", "impel-apps-launcher"),
|
|
67
|
-
|
|
73
|
+
applicationId,
|
|
68
74
|
"darwin",
|
|
69
75
|
home,
|
|
70
76
|
);
|
|
@@ -73,6 +79,78 @@ function macCandidates(tool, home, applicationsRoot) {
|
|
|
73
79
|
return candidates;
|
|
74
80
|
}
|
|
75
81
|
|
|
82
|
+
function runnerEnvelopeCandidate(envelopePath, launcher, tool, home) {
|
|
83
|
+
if (!regularFile(envelopePath) || !regularFile(launcher)) return null;
|
|
84
|
+
let envelope;
|
|
85
|
+
try {
|
|
86
|
+
const raw = fs.readFileSync(envelopePath, "utf8");
|
|
87
|
+
if (Buffer.byteLength(raw, "utf8") > 512 * 1024) return null;
|
|
88
|
+
envelope = JSON.parse(raw);
|
|
89
|
+
} catch {
|
|
90
|
+
return null;
|
|
91
|
+
}
|
|
92
|
+
const payload = envelope?.payload;
|
|
93
|
+
const tenantId = payload?.tenant?.id;
|
|
94
|
+
if (
|
|
95
|
+
envelope?.schemaVersion !== 1
|
|
96
|
+
|| payload?.kind !== "com.useimpel.managed-application-descriptor"
|
|
97
|
+
|| payload?.runtimeContract?.entrypoint !== "engine/main.mjs"
|
|
98
|
+
|| payload?.application?.id !== tool
|
|
99
|
+
|| payload?.application?.adapter !== tool
|
|
100
|
+
|| !TENANT.test(tenantId || "")
|
|
101
|
+
|| String(tenantId).includes("..")
|
|
102
|
+
|| payload?.logicalApplicationId !== `${tenantId}.${tool}`
|
|
103
|
+
) return null;
|
|
104
|
+
const credential = path.join(home, ".config", "impel", "apps", "credentials", `${tenantId}.json`);
|
|
105
|
+
if (!regularFile(credential)) return null;
|
|
106
|
+
return {
|
|
107
|
+
tenantId,
|
|
108
|
+
tenantDisplayName: typeof payload.tenant.displayName === "string" ? payload.tenant.displayName : tenantId,
|
|
109
|
+
launcher,
|
|
110
|
+
logicalApplicationId: payload.logicalApplicationId,
|
|
111
|
+
managedRunner: true,
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
function managedRunnerMacCandidates(tool, home, descriptorRoot, runnerLauncher) {
|
|
116
|
+
if (!regularFile(runnerLauncher)) return [];
|
|
117
|
+
let entries;
|
|
118
|
+
try {
|
|
119
|
+
entries = fs.readdirSync(descriptorRoot, { withFileTypes: true });
|
|
120
|
+
} catch {
|
|
121
|
+
return [];
|
|
122
|
+
}
|
|
123
|
+
const candidates = [];
|
|
124
|
+
for (const entry of entries.sort((left, right) => left.name.localeCompare(right.name))) {
|
|
125
|
+
if (!entry.isDirectory() || !entry.name.endsWith(`.${tool}`)) continue;
|
|
126
|
+
const directory = path.join(descriptorRoot, entry.name);
|
|
127
|
+
let envelopes;
|
|
128
|
+
try {
|
|
129
|
+
envelopes = fs.readdirSync(directory, { withFileTypes: true });
|
|
130
|
+
} catch {
|
|
131
|
+
continue;
|
|
132
|
+
}
|
|
133
|
+
for (const envelope of envelopes.sort((left, right) => left.name.localeCompare(right.name))) {
|
|
134
|
+
if (!envelope.isFile() || !envelope.name.endsWith(".json")) continue;
|
|
135
|
+
const candidate = runnerEnvelopeCandidate(path.join(directory, envelope.name), runnerLauncher, tool, home);
|
|
136
|
+
if (!candidate || candidate.logicalApplicationId !== entry.name) continue;
|
|
137
|
+
candidates.push(candidate);
|
|
138
|
+
break;
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
return candidates;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
function macCandidates(tool, home, applicationsRoot, descriptorRoot, runnerLauncher) {
|
|
145
|
+
const preferred = managedRunnerMacCandidates(tool, home, descriptorRoot, runnerLauncher);
|
|
146
|
+
const legacy = legacyMacCandidates(tool, home, applicationsRoot);
|
|
147
|
+
const byTenant = new Map();
|
|
148
|
+
for (const candidate of [...preferred, ...legacy]) {
|
|
149
|
+
if (!byTenant.has(candidate.tenantId)) byTenant.set(candidate.tenantId, candidate);
|
|
150
|
+
}
|
|
151
|
+
return [...byTenant.values()];
|
|
152
|
+
}
|
|
153
|
+
|
|
76
154
|
function windowsCandidates(tool, home, applicationsRoot) {
|
|
77
155
|
const candidates = [];
|
|
78
156
|
let tenants;
|
|
@@ -83,15 +161,19 @@ function windowsCandidates(tool, home, applicationsRoot) {
|
|
|
83
161
|
}
|
|
84
162
|
for (const tenant of tenants) {
|
|
85
163
|
if (!tenant.isDirectory() || !TENANT.test(tenant.name) || tenant.name.includes("..")) continue;
|
|
86
|
-
const
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
164
|
+
for (const applicationId of APPLICATIONS_BY_TOOL[tool]) {
|
|
165
|
+
const root = path.join(applicationsRoot, tenant.name, applicationId);
|
|
166
|
+
const candidate = parseCandidate(
|
|
167
|
+
path.join(root, "resources", "app-manifest.json"),
|
|
168
|
+
path.join(root, "impel-apps-launcher.exe"),
|
|
169
|
+
applicationId,
|
|
170
|
+
"win32",
|
|
171
|
+
home,
|
|
172
|
+
);
|
|
173
|
+
if (!candidate) continue;
|
|
174
|
+
candidates.push(candidate);
|
|
175
|
+
break;
|
|
176
|
+
}
|
|
95
177
|
}
|
|
96
178
|
return candidates;
|
|
97
179
|
}
|
|
@@ -102,11 +184,15 @@ export function installedManagedAppCandidates(tool, {
|
|
|
102
184
|
applicationsRoot = platform === "win32"
|
|
103
185
|
? path.join(process.env.ProgramFiles || "C:\\Program Files", "Impel", "Apps")
|
|
104
186
|
: "/Applications",
|
|
187
|
+
descriptorRoot = MAC_DESCRIPTOR_ROOT,
|
|
188
|
+
runnerLauncher = MAC_RUNNER,
|
|
105
189
|
} = {}) {
|
|
106
|
-
if (!
|
|
190
|
+
if (!APPLICATIONS_BY_TOOL[tool]) return [];
|
|
107
191
|
const candidates = platform === "win32"
|
|
108
192
|
? windowsCandidates(tool, home, applicationsRoot)
|
|
109
|
-
: platform === "darwin"
|
|
193
|
+
: platform === "darwin"
|
|
194
|
+
? macCandidates(tool, home, applicationsRoot, descriptorRoot, runnerLauncher)
|
|
195
|
+
: [];
|
|
110
196
|
return candidates.sort((left, right) => left.tenantId.localeCompare(right.tenantId));
|
|
111
197
|
}
|
|
112
198
|
|
|
@@ -170,8 +256,11 @@ export function runManagedAppCli(candidate, tool, argv, {
|
|
|
170
256
|
cwd = process.cwd(),
|
|
171
257
|
spawnProcess = spawn,
|
|
172
258
|
} = {}) {
|
|
259
|
+
const args = candidate.managedRunner === true
|
|
260
|
+
? ["--descriptor", candidate.logicalApplicationId, "--managed-cli", tool, "--", ...argv]
|
|
261
|
+
: ["--managed-cli", tool, "--", ...argv];
|
|
173
262
|
return new Promise((resolve) => {
|
|
174
|
-
const child = spawnProcess(candidate.launcher,
|
|
263
|
+
const child = spawnProcess(candidate.launcher, args, {
|
|
175
264
|
cwd,
|
|
176
265
|
env: environment,
|
|
177
266
|
stdio: "inherit",
|
|
@@ -191,4 +280,3 @@ export function runManagedAppCli(candidate, tool, argv, {
|
|
|
191
280
|
});
|
|
192
281
|
});
|
|
193
282
|
}
|
|
194
|
-
|