impel-cli 0.20.1 → 0.20.2-beta.1
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/package.json +1 -1
- package/src/agents.js +409 -184
- package/src/apps.js +5 -3
- package/src/commands/mcp.js +167 -2
- package/src/nativeAgentTransport.js +1981 -0
- package/src/selfInvocation.js +28 -0
package/src/apps.js
CHANGED
|
@@ -107,8 +107,8 @@ export const PINNED_VENDOR_APPS = Object.freeze({
|
|
|
107
107
|
// The Microsoft Store manifest identifies this exact reviewed build.
|
|
108
108
|
// Keep one Windows package version so the manifest contract and local
|
|
109
109
|
// AppX validation cannot silently drift apart again.
|
|
110
|
-
packageVersion: "26.
|
|
111
|
-
codexVersion: "0.
|
|
110
|
+
packageVersion: "26.730.8199.0",
|
|
111
|
+
codexVersion: "0.147.0-alpha.1.2",
|
|
112
112
|
publisherId: "2p2nqsd0c76g0",
|
|
113
113
|
executable: "app\\ChatGPT.exe",
|
|
114
114
|
updateManifestUrl: "https://persistent.oaistatic.com/codex-app-prod/windows-store-update.json",
|
|
@@ -274,7 +274,9 @@ export function managedAppIdentity(target, tenantId = null, tenantName = null) {
|
|
|
274
274
|
// unsupported-selection "Reset to default" treatment.
|
|
275
275
|
// 27: register the separate tenant-bound Tasks MCP server in managed Claude
|
|
276
276
|
// and ChatGPT/Codex profiles without changing the specialist MCP server.
|
|
277
|
-
|
|
277
|
+
// 28: bind generated native-agent profiles to the durable local composite MCP
|
|
278
|
+
// transport and remove model-controlled upstream start/read polling.
|
|
279
|
+
export const CURRENT_CONFIG_VERSION = 28;
|
|
278
280
|
|
|
279
281
|
// Identifies the bundle-BUILDING logic — the asar patches, plist rewrites,
|
|
280
282
|
// helper rebranding, and signing. A vendored bundle is rebuilt only when this
|
package/src/commands/mcp.js
CHANGED
|
@@ -8,6 +8,15 @@ import {
|
|
|
8
8
|
resolveDefaultGateway,
|
|
9
9
|
} from "../config.js";
|
|
10
10
|
import { parseFlags } from "../args.js";
|
|
11
|
+
import {
|
|
12
|
+
NATIVE_AGENT_RECOVER_TOOL,
|
|
13
|
+
NATIVE_AGENT_RESUME_TOOL,
|
|
14
|
+
NATIVE_AGENT_RUN_TOOL,
|
|
15
|
+
NativeAgentCompositeTransport,
|
|
16
|
+
nativeAgentCompositeTools,
|
|
17
|
+
nativeAgentToolCallResult,
|
|
18
|
+
} from "../nativeAgentTransport.js";
|
|
19
|
+
import { IMPEL_NATIVE_AGENT_MCP_TARGET } from "../selfInvocation.js";
|
|
11
20
|
import { ensureTenantSelection, normalizeTenantId, tenantCredential } from "../tenants.js";
|
|
12
21
|
|
|
13
22
|
const TASKS_TARGET = "tasks";
|
|
@@ -168,16 +177,142 @@ function tasksJsonRpcHttpError(id, contentType, body, httpStatus) {
|
|
|
168
177
|
return JSON.stringify({ jsonrpc: "2.0", id: id ?? null, error });
|
|
169
178
|
}
|
|
170
179
|
|
|
180
|
+
function nativeRpcResult(id, result) {
|
|
181
|
+
return JSON.stringify({ jsonrpc: "2.0", id, result });
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
function nativeProgressToken(message) {
|
|
185
|
+
const token = message?.params?._meta?.progressToken;
|
|
186
|
+
return typeof token === "string" || (typeof token === "number" && Number.isFinite(token))
|
|
187
|
+
? token
|
|
188
|
+
: null;
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
/** Run the isolated local composite MCP server without changing proxy mode. */
|
|
192
|
+
export function runNativeAgentMcpServer({
|
|
193
|
+
transport,
|
|
194
|
+
input = process.stdin,
|
|
195
|
+
output = process.stdout,
|
|
196
|
+
recoveryOnly = false,
|
|
197
|
+
}) {
|
|
198
|
+
const lines = readline.createInterface({ input, crlfDelay: Infinity });
|
|
199
|
+
const active = new Map();
|
|
200
|
+
const pending = new Set();
|
|
201
|
+
let progress = 0;
|
|
202
|
+
const write = (value) => output.write(`${value}\n`);
|
|
203
|
+
|
|
204
|
+
function schedule(message) {
|
|
205
|
+
const request = tasksJsonRpcRequestId(message);
|
|
206
|
+
if (!request.valid) {
|
|
207
|
+
write(rpcError(request.id, "Invalid JSON-RPC request."));
|
|
208
|
+
return;
|
|
209
|
+
}
|
|
210
|
+
if (message.method === "notifications/initialized") return;
|
|
211
|
+
if (message.method === "notifications/cancelled") {
|
|
212
|
+
active.get(message.params?.requestId)?.abort();
|
|
213
|
+
return;
|
|
214
|
+
}
|
|
215
|
+
if (!Object.hasOwn(message, "id")) return;
|
|
216
|
+
|
|
217
|
+
const controller = new AbortController();
|
|
218
|
+
active.set(message.id, controller);
|
|
219
|
+
const task = (async () => {
|
|
220
|
+
try {
|
|
221
|
+
if (message.method === "initialize") {
|
|
222
|
+
write(nativeRpcResult(message.id, {
|
|
223
|
+
protocolVersion: "2025-06-18",
|
|
224
|
+
capabilities: { tools: {} },
|
|
225
|
+
serverInfo: { name: "impel-native-agent", version: "1.0.0" },
|
|
226
|
+
}));
|
|
227
|
+
return;
|
|
228
|
+
}
|
|
229
|
+
if (message.method === "ping") {
|
|
230
|
+
write(nativeRpcResult(message.id, {}));
|
|
231
|
+
return;
|
|
232
|
+
}
|
|
233
|
+
if (message.method === "tools/list") {
|
|
234
|
+
write(nativeRpcResult(message.id, { tools: nativeAgentCompositeTools({ recoveryOnly }) }));
|
|
235
|
+
return;
|
|
236
|
+
}
|
|
237
|
+
if (message.method !== "tools/call") {
|
|
238
|
+
throw new Error("unsupported native-agent MCP method");
|
|
239
|
+
}
|
|
240
|
+
const name = message.params?.name;
|
|
241
|
+
const args = message.params?.arguments ?? {};
|
|
242
|
+
const progressToken = nativeProgressToken(message);
|
|
243
|
+
const onProgress = progressToken === null ? undefined : ({ status }) => {
|
|
244
|
+
progress += 1;
|
|
245
|
+
write(JSON.stringify({
|
|
246
|
+
jsonrpc: "2.0",
|
|
247
|
+
method: "notifications/progress",
|
|
248
|
+
params: { progressToken, progress, message: `native-agent run ${status}` },
|
|
249
|
+
}));
|
|
250
|
+
};
|
|
251
|
+
let value;
|
|
252
|
+
if (name === NATIVE_AGENT_RUN_TOOL) {
|
|
253
|
+
if (recoveryOnly) throw new Error("retired native-agent bindings cannot start new runs");
|
|
254
|
+
value = await transport.run(args, { signal: controller.signal, onProgress });
|
|
255
|
+
} else if (name === NATIVE_AGENT_RESUME_TOOL) {
|
|
256
|
+
value = await transport.resume(args, { signal: controller.signal, onProgress });
|
|
257
|
+
} else if (name === NATIVE_AGENT_RECOVER_TOOL) {
|
|
258
|
+
value = transport.recover(args);
|
|
259
|
+
} else {
|
|
260
|
+
throw new Error("unsupported native-agent MCP tool");
|
|
261
|
+
}
|
|
262
|
+
write(nativeRpcResult(message.id, nativeAgentToolCallResult(value)));
|
|
263
|
+
} catch (error) {
|
|
264
|
+
const cancelled = error?.name === "AbortError";
|
|
265
|
+
write(JSON.stringify({
|
|
266
|
+
jsonrpc: "2.0",
|
|
267
|
+
id: message.id,
|
|
268
|
+
error: {
|
|
269
|
+
code: cancelled ? -32800 : -32000,
|
|
270
|
+
message: cancelled
|
|
271
|
+
? "Native-agent attachment cancelled; resume it with the same handle."
|
|
272
|
+
: redactSecretText(error?.message || error),
|
|
273
|
+
},
|
|
274
|
+
}));
|
|
275
|
+
} finally {
|
|
276
|
+
active.delete(message.id);
|
|
277
|
+
}
|
|
278
|
+
})();
|
|
279
|
+
pending.add(task);
|
|
280
|
+
task.finally(() => pending.delete(task));
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
lines.on("line", (line) => {
|
|
284
|
+
const trimmed = line.trim();
|
|
285
|
+
if (!trimmed) return;
|
|
286
|
+
try {
|
|
287
|
+
schedule(JSON.parse(trimmed));
|
|
288
|
+
} catch {
|
|
289
|
+
write(rpcError(null, "Invalid JSON-RPC request."));
|
|
290
|
+
}
|
|
291
|
+
});
|
|
292
|
+
return new Promise((resolve) => {
|
|
293
|
+
lines.on("close", async () => {
|
|
294
|
+
for (const controller of active.values()) controller.abort();
|
|
295
|
+
await Promise.allSettled([...pending]);
|
|
296
|
+
resolve();
|
|
297
|
+
});
|
|
298
|
+
});
|
|
299
|
+
}
|
|
300
|
+
|
|
171
301
|
export async function cmdMcp(argv = []) {
|
|
172
302
|
const { flags, positionals } = parseFlags(argv, {
|
|
173
303
|
target: { type: "string" },
|
|
174
304
|
tenant: { type: "string" },
|
|
305
|
+
"agent-id": { type: "string" },
|
|
306
|
+
"scope-param": { type: "string" },
|
|
307
|
+
"policy-fingerprint": { type: "string" },
|
|
308
|
+
"recovery-only": { type: "boolean" },
|
|
175
309
|
});
|
|
176
310
|
const targetSpecified = Object.hasOwn(flags, "target");
|
|
177
|
-
if (targetSpecified && flags.target
|
|
178
|
-
throw new Error("unsupported MCP target; expected `--target tasks`");
|
|
311
|
+
if (targetSpecified && ![TASKS_TARGET, IMPEL_NATIVE_AGENT_MCP_TARGET].includes(flags.target)) {
|
|
312
|
+
throw new Error("unsupported MCP target; expected `--target tasks` or `--target native-agent`");
|
|
179
313
|
}
|
|
180
314
|
const tasksTarget = flags.target === TASKS_TARGET;
|
|
315
|
+
const nativeAgentTarget = flags.target === IMPEL_NATIVE_AGENT_MCP_TARGET;
|
|
181
316
|
if (tasksTarget) {
|
|
182
317
|
const unsupportedFlags = Object.keys(flags).filter((name) => !["target", "tenant"].includes(name));
|
|
183
318
|
if (unsupportedFlags.length > 0 || positionals.length > 0) {
|
|
@@ -187,6 +322,23 @@ export async function cmdMcp(argv = []) {
|
|
|
187
322
|
throw new Error("Tasks MCP requires a fixed `--tenant <tenant>` argument");
|
|
188
323
|
}
|
|
189
324
|
}
|
|
325
|
+
if (nativeAgentTarget) {
|
|
326
|
+
const expectedFlags = ["target", "tenant", "agent-id", "scope-param", "policy-fingerprint", "recovery-only"];
|
|
327
|
+
const unsupportedFlags = Object.keys(flags).filter((name) => !expectedFlags.includes(name));
|
|
328
|
+
if (unsupportedFlags.length > 0 || positionals.length > 0) {
|
|
329
|
+
throw new Error("unsupported native-agent MCP arguments");
|
|
330
|
+
}
|
|
331
|
+
for (const flag of ["tenant", "agent-id", "scope-param", "policy-fingerprint"]) {
|
|
332
|
+
if (typeof flags[flag] !== "string" || !flags[flag].trim()) {
|
|
333
|
+
throw new Error(`native-agent MCP requires a fixed --${flag} argument`);
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
} else if (!tasksTarget && (Object.hasOwn(flags, "agent-id")
|
|
337
|
+
|| Object.hasOwn(flags, "scope-param")
|
|
338
|
+
|| Object.hasOwn(flags, "policy-fingerprint")
|
|
339
|
+
|| Object.hasOwn(flags, "recovery-only"))) {
|
|
340
|
+
throw new Error("native-agent binding flags require `--target native-agent`");
|
|
341
|
+
}
|
|
190
342
|
const config = loadConfig();
|
|
191
343
|
if (!config?.pat) {
|
|
192
344
|
throw new Error("not authenticated; run `impel setup` (or `impel auth`) first");
|
|
@@ -196,6 +348,19 @@ export async function cmdMcp(argv = []) {
|
|
|
196
348
|
: (await ensureTenantSelection(config)).tenantId;
|
|
197
349
|
const gatewayUrl = config.gatewayUrl || resolveDefaultGateway();
|
|
198
350
|
const credential = tasksTarget ? null : tenantCredential(config.pat, tenantId);
|
|
351
|
+
if (nativeAgentTarget) {
|
|
352
|
+
return runNativeAgentMcpServer({
|
|
353
|
+
transport: new NativeAgentCompositeTransport({
|
|
354
|
+
tenantId,
|
|
355
|
+
agentId: flags["agent-id"],
|
|
356
|
+
scopeParam: flags["scope-param"],
|
|
357
|
+
policyFingerprint: flags["policy-fingerprint"],
|
|
358
|
+
gatewayUrl,
|
|
359
|
+
credential,
|
|
360
|
+
}),
|
|
361
|
+
recoveryOnly: flags["recovery-only"] === true,
|
|
362
|
+
});
|
|
363
|
+
}
|
|
199
364
|
const endpoint = tasksTarget ? null : `${gatewayUrl}/mcp`;
|
|
200
365
|
const input = readline.createInterface({ input: process.stdin, crlfDelay: Infinity });
|
|
201
366
|
let sessionId;
|