@supercorks/krnl 0.1.0 → 0.1.2
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 +35 -5
- package/dist/kernel-companion.mjs +481 -30
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# Kernel CLI
|
|
2
2
|
|
|
3
|
-
Connect [Kernel](https://app.krnl.work) to Codex on your Mac.
|
|
4
|
-
|
|
3
|
+
Connect [Kernel](https://app.krnl.work) to Codex on your Mac. Choose **Launch in Codex** on a Kernel task, review Plan/Work mode, destination, model, reasoning,
|
|
4
|
+
and folder options in the popup, then open the same task in Codex. Conversations and approvals stay in Codex; Kernel
|
|
5
5
|
shows execution status and a direct link.
|
|
6
6
|
|
|
7
7
|
## Install and connect
|
|
@@ -14,6 +14,8 @@ krnl login
|
|
|
14
14
|
krnl connect codex
|
|
15
15
|
```
|
|
16
16
|
|
|
17
|
+
If pnpm reports `ERR_PNPM_NO_GLOBAL_BIN_DIR`, run `pnpm setup`, open a new Terminal tab, and retry the install.
|
|
18
|
+
|
|
17
19
|
`krnl login` opens Kernel in your default browser. Sign in with your invited Kernel account and
|
|
18
20
|
choose **Connect CLI**. Return to Terminal when the browser says the login is finishing.
|
|
19
21
|
|
|
@@ -24,8 +26,12 @@ instructions if the new hooks need review. Review the eight Kernel hooks and res
|
|
|
24
26
|
tasks afterward. The companion detects completed review automatically.
|
|
25
27
|
|
|
26
28
|
Open **Settings → Integrations → Codex** in Kernel to map an organization or project to a saved
|
|
27
|
-
Codex project. Your Mac and saved projects appear automatically.
|
|
28
|
-
|
|
29
|
+
Codex project. Your Mac and saved projects appear automatically. Each connection card contains its organization and
|
|
30
|
+
project mappings. Choose **Add mapping** or **Edit** to set the destination, model, and reasoning.
|
|
31
|
+
New mappings default to **GPT-6 Astra · xhigh**; choices come from that Mac’s current Codex model
|
|
32
|
+
catalog. Launches stay disabled until setup is ready; one unavailable project does not disable
|
|
33
|
+
healthy projects. **Delete connection** revokes its authorization and removes its mappings, while
|
|
34
|
+
keeping existing tasks, handoff history, receipts, and worktrees.
|
|
29
35
|
|
|
30
36
|
No repository checkout, build tools, copied IDs, or per-folder authorization commands are needed.
|
|
31
37
|
Installing the npm package alone does not start a service or change Codex configuration.
|
|
@@ -50,6 +56,10 @@ pnpm add -g @supercorks/krnl@latest
|
|
|
50
56
|
krnl connect codex
|
|
51
57
|
```
|
|
52
58
|
|
|
59
|
+
Version **0.1.1 or later** is required to launch with mapping model and reasoning settings.
|
|
60
|
+
Version **0.1.2 or later** also supports linking an existing Codex task.
|
|
61
|
+
Kernel explains when an older companion needs this update; existing task monitoring continues.
|
|
62
|
+
|
|
53
63
|
Repeated connection reuses the machine identity. Review changed hook commands in `/hooks` if Node
|
|
54
64
|
moved. After updating Node, run `krnl connect codex` to refresh the service’s executable path.
|
|
55
65
|
|
|
@@ -74,6 +84,26 @@ Existing companion installations keep their allowlist until you explicitly upgra
|
|
|
74
84
|
`krnl login` and `krnl connect codex`. The upgrade retains their machine identity, mappings, and
|
|
75
85
|
handoff history when the existing connection is still authorized.
|
|
76
86
|
|
|
87
|
+
## Link an existing task
|
|
88
|
+
|
|
89
|
+
On a Kernel task, choose **Link existing task**. Search by the current Codex task title
|
|
90
|
+
(at least three characters) or paste a `codex://threads/<task-id>` link, select the match,
|
|
91
|
+
and choose **Link task**. Choose a Mac if more than one is connected. Only tasks in
|
|
92
|
+
compatible, locally authorized saved projects appear. Archived tasks are labeled.
|
|
93
|
+
|
|
94
|
+
Linking adds monitoring and a direct Codex link; it never starts a turn, changes its model,
|
|
95
|
+
or changes its folder. A Codex task can be associated with one Kernel task per Mac;
|
|
96
|
+
linking it again to that same task returns the existing association.
|
|
97
|
+
|
|
98
|
+
Search uses a short-lived local metadata cache and never searches messages or previews.
|
|
99
|
+
Kernel receives at most 25 matching titles and destination metadata per lookup. Searches
|
|
100
|
+
expire after 30 seconds, with resolved matches available for two minutes. Refine a broad
|
|
101
|
+
query or paste a deep link if the catalog cannot be searched in time.
|
|
102
|
+
|
|
103
|
+
Completed tasks become Done after their saved turn metadata is checked. A task already
|
|
104
|
+
executing or awaiting input when linked can remain Disconnected until its next status hook;
|
|
105
|
+
continue in Codex normally. Subsequent hooks provide Running, waiting, and Done transitions.
|
|
106
|
+
|
|
77
107
|
## Local data and troubleshooting
|
|
78
108
|
|
|
79
109
|
The executable is copied to a stable location under
|
|
@@ -91,7 +121,7 @@ revoked the Mac remotely, sign in again with `krnl login` before reconnecting. I
|
|
|
91
121
|
reach Kernel, the disconnect command stops the local service and asks you to retry online.
|
|
92
122
|
|
|
93
123
|
Disconnect and logout preserve Codex tasks, local creation receipts, and worktrees. Hooks retain
|
|
94
|
-
only lifecycle metadata for tasks
|
|
124
|
+
only lifecycle metadata for tasks launched or explicitly linked through this connection. Neither transcripts nor attachment
|
|
95
125
|
contents are uploaded. Keep receipts intact when investigating an uncertain launch; the companion
|
|
96
126
|
will reconcile creation before retrying an acknowledgement and will not repeat an uncertain turn.
|
|
97
127
|
|
|
@@ -12425,12 +12425,12 @@ function describe(description) {
|
|
|
12425
12425
|
return ch;
|
|
12426
12426
|
}
|
|
12427
12427
|
// @__NO_SIDE_EFFECTS__
|
|
12428
|
-
function meta(
|
|
12428
|
+
function meta(metadata2) {
|
|
12429
12429
|
const ch = new $ZodCheck({ check: "meta" });
|
|
12430
12430
|
ch._zod.onattach = [
|
|
12431
12431
|
(inst) => {
|
|
12432
12432
|
const existing = globalRegistry.get(inst) ?? {};
|
|
12433
|
-
globalRegistry.add(inst, { ...existing, ...
|
|
12433
|
+
globalRegistry.add(inst, { ...existing, ...metadata2 });
|
|
12434
12434
|
}
|
|
12435
12435
|
];
|
|
12436
12436
|
ch._zod.check = () => {
|
|
@@ -15659,15 +15659,15 @@ async function writeJson(path, value) {
|
|
|
15659
15659
|
async function processLock(directory) {
|
|
15660
15660
|
const port = 4e4 + createHash("sha256").update(directory).digest().readUInt16BE(0) % 2e4;
|
|
15661
15661
|
const server = createServer((socket) => socket.destroy());
|
|
15662
|
-
await new Promise((
|
|
15662
|
+
await new Promise((resolve3, reject) => {
|
|
15663
15663
|
server.once(
|
|
15664
15664
|
"error",
|
|
15665
15665
|
() => reject(new Error("A companion already owns this pairing, or its local lock port is in use"))
|
|
15666
15666
|
);
|
|
15667
|
-
server.listen({ host: "127.0.0.1", port, exclusive: true },
|
|
15667
|
+
server.listen({ host: "127.0.0.1", port, exclusive: true }, resolve3);
|
|
15668
15668
|
});
|
|
15669
15669
|
return async () => {
|
|
15670
|
-
await new Promise((
|
|
15670
|
+
await new Promise((resolve3) => server.close(() => resolve3()));
|
|
15671
15671
|
};
|
|
15672
15672
|
}
|
|
15673
15673
|
function processAlive(pid) {
|
|
@@ -15710,12 +15710,12 @@ async function readCredential(id, keychainService = service) {
|
|
|
15710
15710
|
async function saveCredential(id, token, keychainService = service) {
|
|
15711
15711
|
external_exports.uuid().parse(id);
|
|
15712
15712
|
external_exports.string().regex(/^[A-Za-z0-9_-]{43,128}$/).parse(token);
|
|
15713
|
-
await new Promise((
|
|
15713
|
+
await new Promise((resolve3, reject) => {
|
|
15714
15714
|
const child = spawn("/usr/bin/security", ["-i"], { stdio: ["pipe", "ignore", "ignore"] });
|
|
15715
15715
|
child.on("error", reject);
|
|
15716
15716
|
child.on(
|
|
15717
15717
|
"exit",
|
|
15718
|
-
(code) => code === 0 ?
|
|
15718
|
+
(code) => code === 0 ? resolve3() : reject(new Error("Keychain could not save the machine credential"))
|
|
15719
15719
|
);
|
|
15720
15720
|
child.stdin.end(`add-generic-password -U -s "${keychainService}" -a "${id}" -w "${token}"
|
|
15721
15721
|
`);
|
|
@@ -16016,12 +16016,12 @@ var AppServer = class extends EventEmitter {
|
|
|
16016
16016
|
call(method, params, timeoutMs = 3e4) {
|
|
16017
16017
|
if (this.closed) return Promise.reject(new Error("Codex connection closed"));
|
|
16018
16018
|
const id = ++this.nextId;
|
|
16019
|
-
return new Promise((
|
|
16019
|
+
return new Promise((resolve3, reject) => {
|
|
16020
16020
|
const timer = setTimeout(() => {
|
|
16021
16021
|
this.pending.delete(id);
|
|
16022
16022
|
reject(new Error(`Codex ${method} acknowledgement is uncertain`));
|
|
16023
16023
|
}, timeoutMs);
|
|
16024
|
-
this.pending.set(id, { resolve: (value) =>
|
|
16024
|
+
this.pending.set(id, { resolve: (value) => resolve3(value), reject, timer });
|
|
16025
16025
|
this.child.stdin.write(JSON.stringify({ id, method, params }) + "\n");
|
|
16026
16026
|
});
|
|
16027
16027
|
}
|
|
@@ -16041,11 +16041,11 @@ var AppServer = class extends EventEmitter {
|
|
|
16041
16041
|
this.close();
|
|
16042
16042
|
return;
|
|
16043
16043
|
}
|
|
16044
|
-
await new Promise((
|
|
16044
|
+
await new Promise((resolve3, reject) => {
|
|
16045
16045
|
const finish = () => {
|
|
16046
16046
|
clearTimeout(escalate);
|
|
16047
16047
|
clearTimeout(deadline);
|
|
16048
|
-
|
|
16048
|
+
resolve3();
|
|
16049
16049
|
};
|
|
16050
16050
|
const escalate = setTimeout(() => this.child.kill("SIGKILL"), 3e3);
|
|
16051
16051
|
const deadline = setTimeout(() => {
|
|
@@ -22061,6 +22061,25 @@ var reconcileTogglEntrySchema = external_exports.discriminatedUnion("action", [
|
|
|
22061
22061
|
|
|
22062
22062
|
// ../domain/src/codex.ts
|
|
22063
22063
|
var CODEX_PROTOCOL_VERSION = 1;
|
|
22064
|
+
var CODEX_DEFAULT_MODEL = "gpt-6-astra";
|
|
22065
|
+
var CODEX_DEFAULT_REASONING_EFFORT = "xhigh";
|
|
22066
|
+
var CODEX_REASONING_EFFORTS = [
|
|
22067
|
+
"none",
|
|
22068
|
+
"minimal",
|
|
22069
|
+
"low",
|
|
22070
|
+
"medium",
|
|
22071
|
+
"high",
|
|
22072
|
+
"xhigh",
|
|
22073
|
+
"max",
|
|
22074
|
+
"ultra"
|
|
22075
|
+
];
|
|
22076
|
+
var codexReasoningEffortSchema = external_exports.enum(CODEX_REASONING_EFFORTS);
|
|
22077
|
+
var codexModelIdSchema = external_exports.string().trim().min(1).max(200).regex(/^[A-Za-z0-9][A-Za-z0-9._:/-]*$/);
|
|
22078
|
+
var codexModelSchema = external_exports.strictObject({
|
|
22079
|
+
id: codexModelIdSchema,
|
|
22080
|
+
label: external_exports.string().trim().min(1).max(200),
|
|
22081
|
+
reasoningEfforts: external_exports.array(codexReasoningEffortSchema).min(1).max(CODEX_REASONING_EFFORTS.length)
|
|
22082
|
+
});
|
|
22064
22083
|
var protocolVersion = external_exports.literal(CODEX_PROTOCOL_VERSION);
|
|
22065
22084
|
var sequence = external_exports.number().int().nonnegative().max(Number.MAX_SAFE_INTEGER);
|
|
22066
22085
|
var identity = external_exports.string().min(1).max(200);
|
|
@@ -22078,6 +22097,10 @@ var codexCatalogProjectSchema = external_exports.strictObject({
|
|
|
22078
22097
|
var codexHealthSchema = external_exports.strictObject({
|
|
22079
22098
|
reachable: external_exports.boolean(),
|
|
22080
22099
|
hooksReady: external_exports.boolean(),
|
|
22100
|
+
// Older companions cannot parse model settings in strict launch payloads.
|
|
22101
|
+
supportsModelSelection: external_exports.boolean().optional(),
|
|
22102
|
+
supportsThreadLinking: external_exports.boolean().optional(),
|
|
22103
|
+
models: external_exports.array(codexModelSchema).max(100).optional(),
|
|
22081
22104
|
appServerVersion: external_exports.string().max(100),
|
|
22082
22105
|
desktopVersion: external_exports.string().max(100),
|
|
22083
22106
|
issue: external_exports.string().max(500).nullable()
|
|
@@ -22103,6 +22126,8 @@ var saveCodexMappingSchema = external_exports.strictObject({
|
|
|
22103
22126
|
machineId: external_exports.uuid(),
|
|
22104
22127
|
projectId: identity,
|
|
22105
22128
|
checkout: codexCheckoutSchema,
|
|
22129
|
+
model: codexModelIdSchema.default(CODEX_DEFAULT_MODEL),
|
|
22130
|
+
reasoningEffort: codexReasoningEffortSchema.default(CODEX_DEFAULT_REASONING_EFFORT),
|
|
22106
22131
|
version: sequence.default(0)
|
|
22107
22132
|
});
|
|
22108
22133
|
var deleteCodexMappingSchema = external_exports.strictObject({
|
|
@@ -22116,6 +22141,9 @@ var launchCodexTaskSchema = external_exports.strictObject({
|
|
|
22116
22141
|
taskId: external_exports.uuid(),
|
|
22117
22142
|
taskVersion: external_exports.number().int().positive(),
|
|
22118
22143
|
mode: codexModeSchema,
|
|
22144
|
+
model: codexModelIdSchema.optional(),
|
|
22145
|
+
reasoningEffort: codexReasoningEffortSchema.optional(),
|
|
22146
|
+
checkout: codexCheckoutSchema.optional(),
|
|
22119
22147
|
override: external_exports.strictObject({ machineId: external_exports.uuid(), projectId: identity }).optional()
|
|
22120
22148
|
});
|
|
22121
22149
|
var codexLaunchSchema = external_exports.strictObject({
|
|
@@ -22125,6 +22153,8 @@ var codexLaunchSchema = external_exports.strictObject({
|
|
|
22125
22153
|
mode: codexModeSchema,
|
|
22126
22154
|
destination: codexCatalogProjectSchema,
|
|
22127
22155
|
checkout: codexCheckoutSchema,
|
|
22156
|
+
model: codexModelIdSchema.optional(),
|
|
22157
|
+
reasoningEffort: codexReasoningEffortSchema.optional(),
|
|
22128
22158
|
submittedAt: external_exports.iso.datetime(),
|
|
22129
22159
|
expiresAt: external_exports.iso.datetime(),
|
|
22130
22160
|
task: external_exports.strictObject({
|
|
@@ -22196,6 +22226,83 @@ function codexLaunchPrompt(launch) {
|
|
|
22196
22226
|
].join("\n");
|
|
22197
22227
|
}
|
|
22198
22228
|
|
|
22229
|
+
// ../domain/src/codex-threads.ts
|
|
22230
|
+
var CODEX_THREAD_SEARCH_MIN = 3;
|
|
22231
|
+
var CODEX_THREAD_RESULT_LIMIT = 25;
|
|
22232
|
+
var codexTitleQuerySchema = external_exports.string().trim().max(200).refine(
|
|
22233
|
+
(value) => [...value].length >= CODEX_THREAD_SEARCH_MIN,
|
|
22234
|
+
"Enter at least 3 characters to search task titles"
|
|
22235
|
+
);
|
|
22236
|
+
function codexThreadIdFromUrl(value) {
|
|
22237
|
+
try {
|
|
22238
|
+
if (!/^codex:\/\/threads\/[0-9a-f-]+\/?$/i.test(value.trim())) return null;
|
|
22239
|
+
const url2 = new URL(value.trim());
|
|
22240
|
+
if (url2.protocol !== "codex:" || url2.hostname !== "threads" || url2.port || url2.username || url2.password || url2.search || url2.hash)
|
|
22241
|
+
return null;
|
|
22242
|
+
const match = /^\/([^/]+)\/?$/.exec(url2.pathname);
|
|
22243
|
+
const id = external_exports.uuid().safeParse(match?.[1]);
|
|
22244
|
+
return id.success ? id.data.toLowerCase() : null;
|
|
22245
|
+
} catch {
|
|
22246
|
+
return null;
|
|
22247
|
+
}
|
|
22248
|
+
}
|
|
22249
|
+
var base = {
|
|
22250
|
+
protocolVersion: external_exports.literal(1),
|
|
22251
|
+
requestId: external_exports.uuid(),
|
|
22252
|
+
taskId: external_exports.uuid(),
|
|
22253
|
+
machineId: external_exports.uuid()
|
|
22254
|
+
};
|
|
22255
|
+
var startCodexThreadLookupSchema = external_exports.discriminatedUnion("kind", [
|
|
22256
|
+
external_exports.strictObject({ ...base, kind: external_exports.literal("search"), query: codexTitleQuerySchema }),
|
|
22257
|
+
external_exports.strictObject({
|
|
22258
|
+
...base,
|
|
22259
|
+
kind: external_exports.literal("link"),
|
|
22260
|
+
url: external_exports.string().trim().max(200).refine(
|
|
22261
|
+
(value) => codexThreadIdFromUrl(value) !== null,
|
|
22262
|
+
"Paste a codex://threads/<task-id> link"
|
|
22263
|
+
)
|
|
22264
|
+
})
|
|
22265
|
+
]);
|
|
22266
|
+
var codexThreadResultSchema = external_exports.strictObject({
|
|
22267
|
+
id: external_exports.uuid(),
|
|
22268
|
+
title: external_exports.string().trim().min(1).max(300),
|
|
22269
|
+
project: codexCatalogProjectSchema,
|
|
22270
|
+
cwd: external_exports.string().min(1).max(4096),
|
|
22271
|
+
updatedAt: external_exports.iso.datetime(),
|
|
22272
|
+
archived: external_exports.boolean()
|
|
22273
|
+
});
|
|
22274
|
+
var codexThreadLookupWorkSchema = external_exports.strictObject({
|
|
22275
|
+
id: external_exports.uuid(),
|
|
22276
|
+
query: codexTitleQuerySchema.nullable(),
|
|
22277
|
+
threadId: external_exports.uuid().nullable(),
|
|
22278
|
+
expiresAt: external_exports.iso.datetime()
|
|
22279
|
+
}).refine(
|
|
22280
|
+
(value) => value.query === null !== (value.threadId === null),
|
|
22281
|
+
"Choose title search or a task link"
|
|
22282
|
+
);
|
|
22283
|
+
var codexThreadLookupResultSchema = external_exports.strictObject({
|
|
22284
|
+
protocolVersion: external_exports.literal(1),
|
|
22285
|
+
connectionId: external_exports.uuid(),
|
|
22286
|
+
generation: external_exports.number().int().nonnegative(),
|
|
22287
|
+
id: external_exports.uuid(),
|
|
22288
|
+
results: external_exports.array(codexThreadResultSchema).max(CODEX_THREAD_RESULT_LIMIT),
|
|
22289
|
+
hasMore: external_exports.boolean(),
|
|
22290
|
+
error: external_exports.string().max(500).nullable()
|
|
22291
|
+
});
|
|
22292
|
+
var linkCodexThreadSchema = external_exports.strictObject({
|
|
22293
|
+
...base,
|
|
22294
|
+
lookupId: external_exports.uuid(),
|
|
22295
|
+
threadId: external_exports.uuid()
|
|
22296
|
+
});
|
|
22297
|
+
var codexWatchSchema = external_exports.strictObject({
|
|
22298
|
+
id: external_exports.uuid(),
|
|
22299
|
+
machineId: external_exports.uuid(),
|
|
22300
|
+
sequence: external_exports.number().int().nonnegative(),
|
|
22301
|
+
linkedThreadId: external_exports.uuid(),
|
|
22302
|
+
title: external_exports.string().min(1).max(300),
|
|
22303
|
+
destination: codexCatalogProjectSchema
|
|
22304
|
+
});
|
|
22305
|
+
|
|
22199
22306
|
// ../domain/src/cli.ts
|
|
22200
22307
|
var CLI_PROTOCOL_VERSION = 1;
|
|
22201
22308
|
var CLI_LOGIN_TTL_MS = 5 * 6e4;
|
|
@@ -22269,6 +22376,257 @@ var settingsHealthSnapshotSchema = external_exports.object({
|
|
|
22269
22376
|
})
|
|
22270
22377
|
});
|
|
22271
22378
|
|
|
22379
|
+
// src/models.ts
|
|
22380
|
+
var messages = {
|
|
22381
|
+
catalog: "Codex's model catalog could not be read. Reconnect the companion and try again.",
|
|
22382
|
+
model: "The selected model is unavailable on this Mac. Choose another model in Codex settings.",
|
|
22383
|
+
effort: "The selected model does not support this reasoning effort. Update the Codex settings and try again."
|
|
22384
|
+
};
|
|
22385
|
+
var CodexModelSelectionError = class extends Error {
|
|
22386
|
+
constructor(reason) {
|
|
22387
|
+
super(messages[reason]);
|
|
22388
|
+
}
|
|
22389
|
+
};
|
|
22390
|
+
var modelPageSchema = external_exports.object({
|
|
22391
|
+
data: external_exports.array(
|
|
22392
|
+
external_exports.object({
|
|
22393
|
+
model: codexModelIdSchema,
|
|
22394
|
+
displayName: external_exports.string().trim().min(1),
|
|
22395
|
+
supportedReasoningEfforts: external_exports.array(external_exports.object({ reasoningEffort: external_exports.string() }))
|
|
22396
|
+
})
|
|
22397
|
+
),
|
|
22398
|
+
nextCursor: external_exports.string().min(1).nullable().optional()
|
|
22399
|
+
});
|
|
22400
|
+
async function discoverModels(server) {
|
|
22401
|
+
try {
|
|
22402
|
+
const models = /* @__PURE__ */ new Map();
|
|
22403
|
+
const cursors = /* @__PURE__ */ new Set();
|
|
22404
|
+
let cursor;
|
|
22405
|
+
do {
|
|
22406
|
+
const page = modelPageSchema.parse(
|
|
22407
|
+
await server.call("model/list", { limit: 100, ...cursor ? { cursor } : {} }, 5e3)
|
|
22408
|
+
);
|
|
22409
|
+
for (const model of page.data) {
|
|
22410
|
+
const reasoningEfforts = model.supportedReasoningEfforts.flatMap((option) => {
|
|
22411
|
+
const parsed = codexReasoningEffortSchema.safeParse(option.reasoningEffort);
|
|
22412
|
+
return parsed.success ? [parsed.data] : [];
|
|
22413
|
+
});
|
|
22414
|
+
if (!reasoningEfforts.length) continue;
|
|
22415
|
+
models.set(model.model, {
|
|
22416
|
+
id: model.model,
|
|
22417
|
+
label: model.displayName.slice(0, 200),
|
|
22418
|
+
reasoningEfforts: [...new Set(reasoningEfforts)]
|
|
22419
|
+
});
|
|
22420
|
+
if (models.size > 100) throw new CodexModelSelectionError("catalog");
|
|
22421
|
+
}
|
|
22422
|
+
cursor = page.nextCursor ?? void 0;
|
|
22423
|
+
if (cursor) {
|
|
22424
|
+
if (cursors.has(cursor) || cursors.size >= 100)
|
|
22425
|
+
throw new CodexModelSelectionError("catalog");
|
|
22426
|
+
cursors.add(cursor);
|
|
22427
|
+
}
|
|
22428
|
+
} while (cursor);
|
|
22429
|
+
return [...models.values()];
|
|
22430
|
+
} catch {
|
|
22431
|
+
throw new CodexModelSelectionError("catalog");
|
|
22432
|
+
}
|
|
22433
|
+
}
|
|
22434
|
+
function resolveModelSelection(launch, models) {
|
|
22435
|
+
const model = launch.model ?? CODEX_DEFAULT_MODEL;
|
|
22436
|
+
const reasoningEffort = launch.reasoningEffort ?? CODEX_DEFAULT_REASONING_EFFORT;
|
|
22437
|
+
const available = models.find((candidate) => candidate.id === model);
|
|
22438
|
+
if (!available) throw new CodexModelSelectionError("model");
|
|
22439
|
+
if (!available.reasoningEfforts.includes(reasoningEffort))
|
|
22440
|
+
throw new CodexModelSelectionError("effort");
|
|
22441
|
+
return { model, reasoningEffort };
|
|
22442
|
+
}
|
|
22443
|
+
|
|
22444
|
+
// src/threads.ts
|
|
22445
|
+
import { realpath as realpath2, stat as stat2 } from "node:fs/promises";
|
|
22446
|
+
import { isAbsolute as isAbsolute2, relative, resolve } from "node:path";
|
|
22447
|
+
var metadata = external_exports.object({
|
|
22448
|
+
id: external_exports.uuid(),
|
|
22449
|
+
name: external_exports.string().nullable().optional(),
|
|
22450
|
+
projectId: external_exports.string().nullable().optional(),
|
|
22451
|
+
cwd: external_exports.string(),
|
|
22452
|
+
updatedAt: external_exports.number().finite().nonnegative()
|
|
22453
|
+
});
|
|
22454
|
+
var pageSchema = external_exports.object({
|
|
22455
|
+
data: external_exports.array(metadata).max(200),
|
|
22456
|
+
nextCursor: external_exports.string().nullable().optional()
|
|
22457
|
+
});
|
|
22458
|
+
var sourceKinds = [
|
|
22459
|
+
"cli",
|
|
22460
|
+
"vscode",
|
|
22461
|
+
"exec",
|
|
22462
|
+
"appServer",
|
|
22463
|
+
"subAgent",
|
|
22464
|
+
"subAgentReview",
|
|
22465
|
+
"subAgentCompact",
|
|
22466
|
+
"subAgentThreadSpawn",
|
|
22467
|
+
"subAgentOther",
|
|
22468
|
+
"unknown"
|
|
22469
|
+
];
|
|
22470
|
+
var inside = (root, folder) => {
|
|
22471
|
+
const path = relative(root, folder);
|
|
22472
|
+
return !isAbsolute2(path) && path !== ".." && !path.startsWith("../");
|
|
22473
|
+
};
|
|
22474
|
+
async function commonGitDirectory(folder) {
|
|
22475
|
+
try {
|
|
22476
|
+
const { stdout } = await execute("git", ["-C", folder, "rev-parse", "--git-common-dir"], {
|
|
22477
|
+
timeout: 1500,
|
|
22478
|
+
maxBuffer: 8192
|
|
22479
|
+
});
|
|
22480
|
+
return await realpath2(resolve(folder, stdout.trim()));
|
|
22481
|
+
} catch {
|
|
22482
|
+
return null;
|
|
22483
|
+
}
|
|
22484
|
+
}
|
|
22485
|
+
async function resolveThreadProject(thread, pairing, catalog2) {
|
|
22486
|
+
const authorized = catalog2.filter(
|
|
22487
|
+
(project) => !project.issue && (pairing.projectAccess === "all-saved" || pairing.projects.some(
|
|
22488
|
+
(allowed) => allowed.id === project.id && allowed.root === project.root
|
|
22489
|
+
))
|
|
22490
|
+
);
|
|
22491
|
+
let cwd;
|
|
22492
|
+
try {
|
|
22493
|
+
cwd = await realpath2(thread.cwd);
|
|
22494
|
+
if (!(await stat2(cwd)).isDirectory()) return null;
|
|
22495
|
+
} catch {
|
|
22496
|
+
return null;
|
|
22497
|
+
}
|
|
22498
|
+
const candidates = thread.projectId ? authorized.filter((project) => project.id === thread.projectId) : [...authorized].sort((a2, b2) => b2.root.length - a2.root.length);
|
|
22499
|
+
for (const project of candidates) {
|
|
22500
|
+
if (await realpath2(project.root).catch(() => null) !== project.root) continue;
|
|
22501
|
+
if (inside(project.root, cwd)) return { project, cwd };
|
|
22502
|
+
}
|
|
22503
|
+
const common = candidates.some((project) => project.isGit) ? await commonGitDirectory(cwd) : null;
|
|
22504
|
+
if (common)
|
|
22505
|
+
for (const project of candidates) {
|
|
22506
|
+
if (project.isGit && await commonGitDirectory(project.root) === common)
|
|
22507
|
+
return { project, cwd };
|
|
22508
|
+
}
|
|
22509
|
+
return null;
|
|
22510
|
+
}
|
|
22511
|
+
var CodexThreadLookupService = class {
|
|
22512
|
+
constructor(now = () => performance.now()) {
|
|
22513
|
+
this.now = now;
|
|
22514
|
+
}
|
|
22515
|
+
now;
|
|
22516
|
+
cached = null;
|
|
22517
|
+
refreshedAt = 0;
|
|
22518
|
+
loading;
|
|
22519
|
+
index(server) {
|
|
22520
|
+
if (this.cached && this.now() - this.refreshedAt < 3e4) return Promise.resolve(this.cached);
|
|
22521
|
+
if (this.loading) return this.loading;
|
|
22522
|
+
this.loading = (async () => {
|
|
22523
|
+
const threads = [];
|
|
22524
|
+
const started = this.now();
|
|
22525
|
+
for (const archived of [false, true]) {
|
|
22526
|
+
let cursor = null;
|
|
22527
|
+
const visited = /* @__PURE__ */ new Set();
|
|
22528
|
+
do {
|
|
22529
|
+
if (this.now() - started > 2e4 || threads.length > 5e4)
|
|
22530
|
+
throw new Error(
|
|
22531
|
+
"The task catalog is too large to search right now. Paste a Codex task link instead."
|
|
22532
|
+
);
|
|
22533
|
+
const page = pageSchema.parse(
|
|
22534
|
+
await server.call(
|
|
22535
|
+
"thread/list",
|
|
22536
|
+
{
|
|
22537
|
+
limit: 200,
|
|
22538
|
+
archived,
|
|
22539
|
+
modelProviders: [],
|
|
22540
|
+
sourceKinds,
|
|
22541
|
+
useStateDbOnly: true,
|
|
22542
|
+
sortKey: "updated_at",
|
|
22543
|
+
...cursor ? { cursor } : {}
|
|
22544
|
+
},
|
|
22545
|
+
5e3
|
|
22546
|
+
)
|
|
22547
|
+
);
|
|
22548
|
+
threads.push(...page.data.map((thread) => ({ ...thread, archived })));
|
|
22549
|
+
cursor = page.nextCursor ?? null;
|
|
22550
|
+
if (cursor && visited.has(cursor))
|
|
22551
|
+
throw new Error("Codex returned an invalid task catalog. Try again.");
|
|
22552
|
+
if (cursor) visited.add(cursor);
|
|
22553
|
+
} while (cursor);
|
|
22554
|
+
}
|
|
22555
|
+
this.cached = [...new Map(threads.map((thread) => [thread.id, thread])).values()].sort(
|
|
22556
|
+
(a2, b2) => b2.updatedAt - a2.updatedAt || a2.id.localeCompare(b2.id)
|
|
22557
|
+
);
|
|
22558
|
+
this.refreshedAt = this.now();
|
|
22559
|
+
return this.cached;
|
|
22560
|
+
})().finally(() => {
|
|
22561
|
+
this.loading = void 0;
|
|
22562
|
+
});
|
|
22563
|
+
return this.loading;
|
|
22564
|
+
}
|
|
22565
|
+
async lookup(server, raw, pairing, catalog2) {
|
|
22566
|
+
const work = codexThreadLookupWorkSchema.parse(raw);
|
|
22567
|
+
let candidates;
|
|
22568
|
+
if (work.threadId) {
|
|
22569
|
+
const result = external_exports.object({ thread: metadata }).parse(
|
|
22570
|
+
await server.call("thread/read", { threadId: work.threadId, includeTurns: false }, 5e3)
|
|
22571
|
+
);
|
|
22572
|
+
if (result.thread.id !== work.threadId) throw new Error("Codex returned a different task.");
|
|
22573
|
+
candidates = [{ ...result.thread, archived: false }];
|
|
22574
|
+
} else {
|
|
22575
|
+
const query = work.query.toLowerCase();
|
|
22576
|
+
candidates = (await this.index(server)).filter(
|
|
22577
|
+
(thread) => thread.name?.trim().slice(0, 300).toLowerCase().includes(query)
|
|
22578
|
+
);
|
|
22579
|
+
}
|
|
22580
|
+
const results = [];
|
|
22581
|
+
const started = this.now();
|
|
22582
|
+
for (const thread of candidates) {
|
|
22583
|
+
if (this.now() - started > 2e4)
|
|
22584
|
+
throw new Error("Refine the title or paste a Codex task link.");
|
|
22585
|
+
const destination = await resolveThreadProject(thread, pairing, catalog2);
|
|
22586
|
+
if (!destination) continue;
|
|
22587
|
+
if (results.length === CODEX_THREAD_RESULT_LIMIT) return { results, hasMore: true };
|
|
22588
|
+
results.push({
|
|
22589
|
+
id: thread.id,
|
|
22590
|
+
title: thread.name?.trim().slice(0, 300) || "Untitled task",
|
|
22591
|
+
...destination,
|
|
22592
|
+
updatedAt: new Date(thread.updatedAt * 1e3).toISOString(),
|
|
22593
|
+
archived: thread.archived
|
|
22594
|
+
});
|
|
22595
|
+
}
|
|
22596
|
+
return { results, hasMore: false };
|
|
22597
|
+
}
|
|
22598
|
+
};
|
|
22599
|
+
async function linkedReceipt(server, watch, pairing, catalog2) {
|
|
22600
|
+
if (watch.machineId !== pairing.machineId)
|
|
22601
|
+
throw new Error("This task belongs to another machine");
|
|
22602
|
+
const { thread } = external_exports.object({ thread: metadata }).parse(
|
|
22603
|
+
await server.call(
|
|
22604
|
+
"thread/read",
|
|
22605
|
+
{ threadId: watch.linkedThreadId, includeTurns: false },
|
|
22606
|
+
5e3
|
|
22607
|
+
)
|
|
22608
|
+
);
|
|
22609
|
+
if (thread.id !== watch.linkedThreadId) throw new Error("Codex returned a different task");
|
|
22610
|
+
const destination = await resolveThreadProject(thread, pairing, catalog2);
|
|
22611
|
+
if (!destination || destination.project.id !== watch.destination.id || destination.project.root !== watch.destination.root)
|
|
22612
|
+
throw new Error("The saved project is no longer locally authorized");
|
|
22613
|
+
return {
|
|
22614
|
+
launch: watch,
|
|
22615
|
+
preparedAt: Date.now(),
|
|
22616
|
+
phase: "released",
|
|
22617
|
+
threadId: thread.id,
|
|
22618
|
+
cwd: destination.cwd,
|
|
22619
|
+
status: {
|
|
22620
|
+
launchId: watch.id,
|
|
22621
|
+
sequence: watch.sequence + 1,
|
|
22622
|
+
state: "unreachable",
|
|
22623
|
+
waiting: false,
|
|
22624
|
+
turnId: null,
|
|
22625
|
+
message: "Checking the linked task in Codex. Activity is observed from the next status hook."
|
|
22626
|
+
}
|
|
22627
|
+
};
|
|
22628
|
+
}
|
|
22629
|
+
|
|
22272
22630
|
// src/runtime.ts
|
|
22273
22631
|
var sourceMarker = (id) => `kernel-handoff:${id}`;
|
|
22274
22632
|
function initialReceipt(launch) {
|
|
@@ -22287,7 +22645,7 @@ function initialReceipt(launch) {
|
|
|
22287
22645
|
};
|
|
22288
22646
|
}
|
|
22289
22647
|
function canBegin(receipt, now) {
|
|
22290
|
-
return receipt.phase === "prepared" && now < Date.parse(receipt.launch.expiresAt);
|
|
22648
|
+
return receipt.phase === "prepared" && "expiresAt" in receipt.launch && now < Date.parse(receipt.launch.expiresAt);
|
|
22291
22649
|
}
|
|
22292
22650
|
async function findCreation(server, receipt) {
|
|
22293
22651
|
let cursor = null;
|
|
@@ -22316,6 +22674,8 @@ async function runCompanion(machineId, entrypoint2, signal) {
|
|
|
22316
22674
|
const unlock = await processLock(directory);
|
|
22317
22675
|
const owners = /* @__PURE__ */ new Map();
|
|
22318
22676
|
let observer;
|
|
22677
|
+
let lookupServer;
|
|
22678
|
+
let lookupWork;
|
|
22319
22679
|
try {
|
|
22320
22680
|
const pairing = await readJson(join4(directory, "pairing.json"));
|
|
22321
22681
|
if (!pairing?.workspaceId) throw new Error("Complete this machine pairing first");
|
|
@@ -22343,6 +22703,26 @@ async function runCompanion(machineId, entrypoint2, signal) {
|
|
|
22343
22703
|
)
|
|
22344
22704
|
);
|
|
22345
22705
|
const queue = [];
|
|
22706
|
+
const lookupService = new CodexThreadLookupService();
|
|
22707
|
+
let lookupBusy = false;
|
|
22708
|
+
const lookupResults = [];
|
|
22709
|
+
const watched = /* @__PURE__ */ new Map();
|
|
22710
|
+
const watchAttempts = /* @__PURE__ */ new Map();
|
|
22711
|
+
const watchResults = [];
|
|
22712
|
+
let watchCursor = null;
|
|
22713
|
+
const connectLookup = async () => {
|
|
22714
|
+
if (!lookupServer) {
|
|
22715
|
+
lookupServer = new AppServer(directory);
|
|
22716
|
+
try {
|
|
22717
|
+
await lookupServer.initialize();
|
|
22718
|
+
} catch (error51) {
|
|
22719
|
+
lookupServer.close();
|
|
22720
|
+
lookupServer = void 0;
|
|
22721
|
+
throw error51;
|
|
22722
|
+
}
|
|
22723
|
+
}
|
|
22724
|
+
return lookupServer;
|
|
22725
|
+
};
|
|
22346
22726
|
const connectObserver = async () => {
|
|
22347
22727
|
observer?.close();
|
|
22348
22728
|
observer = new AppServer(directory);
|
|
@@ -22353,6 +22733,9 @@ async function runCompanion(machineId, entrypoint2, signal) {
|
|
|
22353
22733
|
let health = {
|
|
22354
22734
|
reachable: false,
|
|
22355
22735
|
hooksReady: false,
|
|
22736
|
+
supportsModelSelection: true,
|
|
22737
|
+
supportsThreadLinking: true,
|
|
22738
|
+
models: [],
|
|
22356
22739
|
appServerVersion: "",
|
|
22357
22740
|
desktopVersion: "",
|
|
22358
22741
|
issue: "Checking Codex compatibility."
|
|
@@ -22418,16 +22801,22 @@ async function runCompanion(machineId, entrypoint2, signal) {
|
|
|
22418
22801
|
() => queue.push({ launchId: launch.id, event: { method: "kernel/closed" } })
|
|
22419
22802
|
);
|
|
22420
22803
|
await owner.initialize();
|
|
22804
|
+
const selection = resolveModelSelection(launch, await discoverModels(owner));
|
|
22805
|
+
if (!canBegin(receipt, Date.now() + clockOffset))
|
|
22806
|
+
throw new Error("The launch expired while checking model availability");
|
|
22807
|
+
receipt.model = selection.model;
|
|
22808
|
+
receipt.effort = selection.reasoningEffort;
|
|
22421
22809
|
receipt.phase = "creating";
|
|
22422
22810
|
await save(receipt);
|
|
22423
22811
|
const created = await owner.call("thread/start", {
|
|
22424
22812
|
cwd: receipt.cwd,
|
|
22425
22813
|
projectId: project.id,
|
|
22426
|
-
threadSource: sourceMarker(launch.id)
|
|
22814
|
+
threadSource: sourceMarker(launch.id),
|
|
22815
|
+
model: selection.model,
|
|
22816
|
+
config: { model_reasoning_effort: selection.reasoningEffort },
|
|
22817
|
+
allowProviderModelFallback: false
|
|
22427
22818
|
});
|
|
22428
22819
|
receipt.threadId = created.thread.id;
|
|
22429
|
-
receipt.model = created.model;
|
|
22430
|
-
receipt.effort = created.reasoningEffort ?? null;
|
|
22431
22820
|
receipt.phase = "created";
|
|
22432
22821
|
await save(receipt);
|
|
22433
22822
|
await indexThreads();
|
|
@@ -22442,14 +22831,14 @@ async function runCompanion(machineId, entrypoint2, signal) {
|
|
|
22442
22831
|
input: [{ type: "text", text: codexLaunchPrompt(launch) }],
|
|
22443
22832
|
collaborationMode: collaborationMode(
|
|
22444
22833
|
launch.mode,
|
|
22445
|
-
|
|
22446
|
-
|
|
22834
|
+
selection.model,
|
|
22835
|
+
selection.reasoningEffort
|
|
22447
22836
|
)
|
|
22448
22837
|
});
|
|
22449
22838
|
receipt.turnId = response.turn.id;
|
|
22450
22839
|
receipt.status.turnId = response.turn.id;
|
|
22451
22840
|
await save(receipt);
|
|
22452
|
-
} catch {
|
|
22841
|
+
} catch (error51) {
|
|
22453
22842
|
try {
|
|
22454
22843
|
await owners.get(launch.id)?.stop();
|
|
22455
22844
|
} catch {
|
|
@@ -22474,7 +22863,7 @@ async function runCompanion(machineId, entrypoint2, signal) {
|
|
|
22474
22863
|
};
|
|
22475
22864
|
} else {
|
|
22476
22865
|
receipt.ambiguous = receipt.phase === "creating";
|
|
22477
|
-
receipt.failure = receipt.ambiguous ? "Confirming whether Codex created the task. This launch will not be repeated." : "The task could not start. Check the locally authorized project and checkout policy.";
|
|
22866
|
+
receipt.failure = receipt.ambiguous ? "Confirming whether Codex created the task. This launch will not be repeated." : error51 instanceof CodexModelSelectionError ? error51.message : "The task could not start. Check the locally authorized project and checkout policy.";
|
|
22478
22867
|
if (!receipt.ambiguous) receipt.phase = "failed";
|
|
22479
22868
|
}
|
|
22480
22869
|
await save(receipt);
|
|
@@ -22518,21 +22907,26 @@ async function runCompanion(machineId, entrypoint2, signal) {
|
|
|
22518
22907
|
"Print:CFBundleShortVersionString",
|
|
22519
22908
|
"/Applications/ChatGPT.app/Contents/Info.plist"
|
|
22520
22909
|
]).then((result) => result.stdout.trim()).catch(() => "");
|
|
22910
|
+
const models = await discoverModels(observer);
|
|
22521
22911
|
health = {
|
|
22522
22912
|
reachable: true,
|
|
22523
22913
|
hooksReady: ready,
|
|
22914
|
+
supportsModelSelection: true,
|
|
22915
|
+
supportsThreadLinking: true,
|
|
22916
|
+
models,
|
|
22524
22917
|
appServerVersion: stdout.trim(),
|
|
22525
22918
|
desktopVersion: desktop,
|
|
22526
22919
|
issue: ready ? null : "Review the eight Kernel hooks using /hooks in Codex CLI. The companion detects completed review automatically."
|
|
22527
22920
|
};
|
|
22528
|
-
} catch {
|
|
22921
|
+
} catch (error51) {
|
|
22529
22922
|
observer?.close();
|
|
22530
22923
|
observer = void 0;
|
|
22531
22924
|
health = {
|
|
22532
22925
|
...health,
|
|
22533
22926
|
reachable: false,
|
|
22534
22927
|
hooksReady: false,
|
|
22535
|
-
|
|
22928
|
+
models: [],
|
|
22929
|
+
issue: error51 instanceof CodexModelSelectionError ? error51.message : "Codex could not be reached through its supported app-server interface."
|
|
22536
22930
|
};
|
|
22537
22931
|
}
|
|
22538
22932
|
try {
|
|
@@ -22596,6 +22990,18 @@ async function runCompanion(machineId, entrypoint2, signal) {
|
|
|
22596
22990
|
if (!reconciled || recovered) await indexThreads();
|
|
22597
22991
|
reconciled = true;
|
|
22598
22992
|
}
|
|
22993
|
+
for (const receipt of watchResults.splice(0)) {
|
|
22994
|
+
if (receipts.has(receipt.launch.id)) continue;
|
|
22995
|
+
receipts.set(receipt.launch.id, receipt);
|
|
22996
|
+
await save(receipt);
|
|
22997
|
+
await indexThreads();
|
|
22998
|
+
}
|
|
22999
|
+
if (!networkError) {
|
|
23000
|
+
while (lookupResults.length) {
|
|
23001
|
+
await post("thread-lookup-result", lookupResults[0]);
|
|
23002
|
+
lookupResults.shift();
|
|
23003
|
+
}
|
|
23004
|
+
}
|
|
22599
23005
|
for (const { launchId, event } of queue.splice(0)) {
|
|
22600
23006
|
const receipt = receipts.get(launchId);
|
|
22601
23007
|
if (!receipt || receipt.phase === "released" || receipt.phase === "failed") continue;
|
|
@@ -22710,6 +23116,49 @@ async function runCompanion(machineId, entrypoint2, signal) {
|
|
|
22710
23116
|
}
|
|
22711
23117
|
if (networkError) throw networkError;
|
|
22712
23118
|
if (health.reachable && health.hooksReady && reconciled && Date.now() - tickStarted <= 5e3) {
|
|
23119
|
+
const lookups = await post("thread-lookups", { cursor: watchCursor });
|
|
23120
|
+
watchCursor = lookups.nextCursor;
|
|
23121
|
+
for (const raw of lookups.watches) {
|
|
23122
|
+
const watch = codexWatchSchema.parse(raw);
|
|
23123
|
+
if (watch.machineId === machineId && !receipts.has(watch.id))
|
|
23124
|
+
watched.set(watch.id, watch);
|
|
23125
|
+
}
|
|
23126
|
+
if (!lookupBusy) {
|
|
23127
|
+
const request = lookups.requests.find(
|
|
23128
|
+
(item) => Date.parse(item.expiresAt) > Date.now() + clockOffset
|
|
23129
|
+
);
|
|
23130
|
+
const watch = [...watched.values()].find(
|
|
23131
|
+
(item) => Date.now() - (watchAttempts.get(item.id) ?? 0) > 3e4
|
|
23132
|
+
);
|
|
23133
|
+
if (request || watch) {
|
|
23134
|
+
lookupBusy = true;
|
|
23135
|
+
if (!request && watch) watchAttempts.set(watch.id, Date.now());
|
|
23136
|
+
lookupWork = (async () => {
|
|
23137
|
+
const local = await readJson(join4(directory, "pairing.json"));
|
|
23138
|
+
if (!local) throw new Error("The local connection is unavailable");
|
|
23139
|
+
const server = await connectLookup();
|
|
23140
|
+
if (request) {
|
|
23141
|
+
const result = await lookupService.lookup(server, request, local, catalog2);
|
|
23142
|
+
lookupResults.push({ id: request.id, ...result, error: null });
|
|
23143
|
+
} else if (watch) {
|
|
23144
|
+
watchResults.push(await linkedReceipt(server, watch, local, catalog2));
|
|
23145
|
+
watched.delete(watch.id);
|
|
23146
|
+
}
|
|
23147
|
+
})().catch(() => {
|
|
23148
|
+
lookupServer?.close();
|
|
23149
|
+
lookupServer = void 0;
|
|
23150
|
+
if (request)
|
|
23151
|
+
lookupResults.push({
|
|
23152
|
+
id: request.id,
|
|
23153
|
+
results: [],
|
|
23154
|
+
hasMore: false,
|
|
23155
|
+
error: "The local task could not be read. Check Codex and the saved project, then try again."
|
|
23156
|
+
});
|
|
23157
|
+
}).finally(() => {
|
|
23158
|
+
lookupBusy = false;
|
|
23159
|
+
});
|
|
23160
|
+
}
|
|
23161
|
+
}
|
|
22713
23162
|
const response = await post("launches", {});
|
|
22714
23163
|
for (const launch of response.launches) await begin(codexLaunchSchema.parse(launch));
|
|
22715
23164
|
}
|
|
@@ -22726,6 +23175,8 @@ async function runCompanion(machineId, entrypoint2, signal) {
|
|
|
22726
23175
|
} finally {
|
|
22727
23176
|
await Promise.allSettled([...owners.values()].map((server) => server.stop()));
|
|
22728
23177
|
await observer?.stop().catch(() => void 0);
|
|
23178
|
+
await lookupServer?.stop().catch(() => void 0);
|
|
23179
|
+
await lookupWork;
|
|
22729
23180
|
await unlock();
|
|
22730
23181
|
}
|
|
22731
23182
|
}
|
|
@@ -22783,10 +23234,10 @@ async function signedInProfile() {
|
|
|
22783
23234
|
}
|
|
22784
23235
|
async function loginCallback(state, timeoutMs = 3e5) {
|
|
22785
23236
|
cliSecretSchema.parse(state);
|
|
22786
|
-
let
|
|
23237
|
+
let resolve3;
|
|
22787
23238
|
let reject;
|
|
22788
23239
|
const result = new Promise((yes, no2) => {
|
|
22789
|
-
|
|
23240
|
+
resolve3 = yes;
|
|
22790
23241
|
reject = no2;
|
|
22791
23242
|
});
|
|
22792
23243
|
void result.catch(() => void 0);
|
|
@@ -22823,11 +23274,11 @@ async function loginCallback(state, timeoutMs = 3e5) {
|
|
|
22823
23274
|
`<html><title>Kernel CLI</title><body style="font:18px system-ui;padding:48px"><h1>${cancelled ? "Login cancelled" : "Return to your terminal"}</h1><p>${cancelled ? "No CLI login was granted." : "Kernel is finishing your CLI login. You can close this tab."}</p></body></html>`
|
|
22824
23275
|
);
|
|
22825
23276
|
if (cancelled) reject(new Error("Login cancelled. No connection was created."));
|
|
22826
|
-
else
|
|
23277
|
+
else resolve3(code);
|
|
22827
23278
|
});
|
|
22828
|
-
await new Promise((
|
|
23279
|
+
await new Promise((resolve4, reject2) => {
|
|
22829
23280
|
server.once("error", reject2);
|
|
22830
|
-
server.listen(0, "127.0.0.1",
|
|
23281
|
+
server.listen(0, "127.0.0.1", resolve4);
|
|
22831
23282
|
});
|
|
22832
23283
|
port = server.address().port;
|
|
22833
23284
|
const timer = setTimeout(
|
|
@@ -22837,7 +23288,7 @@ async function loginCallback(state, timeoutMs = 3e5) {
|
|
|
22837
23288
|
const close = async () => {
|
|
22838
23289
|
clearTimeout(timer);
|
|
22839
23290
|
server.closeAllConnections();
|
|
22840
|
-
await new Promise((
|
|
23291
|
+
await new Promise((resolve4) => server.close(() => resolve4()));
|
|
22841
23292
|
};
|
|
22842
23293
|
return { redirectUri: `http://127.0.0.1:${port}/callback`, result, close };
|
|
22843
23294
|
}
|
|
@@ -22918,12 +23369,12 @@ import { createInterface } from "node:readline/promises";
|
|
|
22918
23369
|
// src/setup.ts
|
|
22919
23370
|
import { chmod as chmod2, copyFile, mkdir as mkdir4, rename as rename2, rm } from "node:fs/promises";
|
|
22920
23371
|
import { homedir as homedir4 } from "node:os";
|
|
22921
|
-
import { dirname as dirname2, join as join6, resolve } from "node:path";
|
|
23372
|
+
import { dirname as dirname2, join as join6, resolve as resolve2 } from "node:path";
|
|
22922
23373
|
import { randomUUID as randomUUID5 } from "node:crypto";
|
|
22923
23374
|
var installedEntrypoint = join6(dataRoot, "bin/kernel-companion.mjs");
|
|
22924
23375
|
async function installBundle(entrypoint2) {
|
|
22925
23376
|
await mkdir4(dirname2(installedEntrypoint), { recursive: true, mode: 448 });
|
|
22926
|
-
if (
|
|
23377
|
+
if (resolve2(entrypoint2) !== resolve2(installedEntrypoint)) {
|
|
22927
23378
|
const temporary = `${installedEntrypoint}.${randomUUID5()}.tmp`;
|
|
22928
23379
|
try {
|
|
22929
23380
|
await copyFile(entrypoint2, temporary);
|
|
@@ -23243,7 +23694,7 @@ async function main() {
|
|
|
23243
23694
|
}
|
|
23244
23695
|
if (command === "--version") {
|
|
23245
23696
|
process.stdout.write(
|
|
23246
|
-
`${false ? "development" : "0.1.
|
|
23697
|
+
`${false ? "development" : "0.1.2"}
|
|
23247
23698
|
`
|
|
23248
23699
|
);
|
|
23249
23700
|
return;
|
package/package.json
CHANGED