@gh-symphony/cli 0.0.20 → 0.0.22
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 +66 -2
- package/dist/chunk-2TSM3INR.js +1085 -0
- package/dist/chunk-2UW7NQLX.js +684 -0
- package/dist/{chunk-MVRF7BES.js → chunk-36KYEDEO.js} +10 -1
- package/dist/{chunk-TILHWBP6.js → chunk-C67H3OUL.js} +239 -36
- package/dist/{chunk-C7G7RJ4G.js → chunk-DDL4BWSL.js} +1 -1
- package/dist/{chunk-XN5ABWZ6.js → chunk-DFLXHNYQ.js} +26 -30
- package/dist/{chunk-EKKT5USP.js → chunk-E7HYEEZD.js} +487 -133
- package/dist/chunk-EEQQWTXS.js +3257 -0
- package/dist/chunk-GDE6FYN4.js +26 -0
- package/dist/{chunk-Y6TYJMNT.js → chunk-GSX2FV3M.js} +10 -16
- package/dist/{chunk-RN2PACNV.js → chunk-HMLBBZNY.js} +731 -75
- package/dist/{chunk-5NV3LSAJ.js → chunk-IWFX2FMA.js} +5 -1
- package/dist/{chunk-HZVDTAPS.js → chunk-PUDXVBSN.js} +1549 -1458
- package/dist/{chunk-ROGRTUFI.js → chunk-QIRE2VXS.js} +14 -3
- package/dist/{chunk-3AWF54PI.js → chunk-ZHOKYUO3.js} +394 -42
- package/dist/{config-cmd-DNXNL26Z.js → config-cmd-Z3A7V6NC.js} +1 -1
- package/dist/{doctor-IYHCFXOZ.js → doctor-EJUMPBMW.js} +105 -40
- package/dist/index.js +112 -24
- package/dist/{init-KZT6YNOH.js → init-54HMKNYI.js} +8 -3
- package/dist/{logs-6JKKYDGJ.js → logs-GTZ4U5JE.js} +2 -2
- package/dist/project-RMYMZSFV.js +25 -0
- package/dist/{recover-5KQI7WH5.js → recover-LTLKMTRX.js} +7 -5
- package/dist/repo-WI7GF6XQ.js +749 -0
- package/dist/{run-ETC5UTRA.js → run-IHN3ZL35.js} +21 -7
- package/dist/{setup-VWB7RZUQ.js → setup-TZJSM3QV.js} +53 -14
- package/dist/start-RTAHQMR2.js +19 -0
- package/dist/status-F4D52OVK.js +12 -0
- package/dist/stop-MDKMJPVR.js +10 -0
- package/dist/{upgrade-3YNF3VKY.js → upgrade-O33S2SJK.js} +2 -2
- package/dist/{version-NUBTTOG7.js → version-CW54Q7BK.js} +1 -1
- package/dist/worker-entry.js +848 -693
- package/dist/{workflow-TBIFY5MO.js → workflow-L3KT6HB7.js} +177 -11
- package/package.json +4 -2
- package/dist/chunk-M3IFVLQS.js +0 -1155
- package/dist/project-UUVHS3ZR.js +0 -22
- package/dist/repo-HDDE7OUI.js +0 -321
- package/dist/start-ENFLZUI6.js +0 -16
- package/dist/status-QSCFVGRQ.js +0 -11
- package/dist/stop-7MFCBQVW.js +0 -9
|
@@ -0,0 +1,684 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
buildAgentInputRequiredReason,
|
|
4
|
+
createGitHubGraphQLMcpServerEntry,
|
|
5
|
+
extractEnvForCodex,
|
|
6
|
+
readAgentCredentialCache,
|
|
7
|
+
readEnvFile,
|
|
8
|
+
resolveGitHubGraphQLToken,
|
|
9
|
+
shouldReuseAgentCredentialCache,
|
|
10
|
+
writeAgentCredentialCache
|
|
11
|
+
} from "./chunk-EEQQWTXS.js";
|
|
12
|
+
|
|
13
|
+
// ../runtime-codex/src/runtime.ts
|
|
14
|
+
import { spawn } from "child_process";
|
|
15
|
+
import { copyFile, mkdir, readFile, writeFile } from "fs/promises";
|
|
16
|
+
import { join } from "path";
|
|
17
|
+
import { homedir } from "os";
|
|
18
|
+
import { fileURLToPath } from "url";
|
|
19
|
+
var DEFAULT_GITHUB_GIT_HOST = "github.com";
|
|
20
|
+
var DEFAULT_GITHUB_GIT_USERNAME = "x-access-token";
|
|
21
|
+
var STAGED_CODEX_HOME_DIRNAME = ".codex-agent";
|
|
22
|
+
var DIRECT_AGENT_ENV_KEYS = [
|
|
23
|
+
"OPENAI_API_KEY",
|
|
24
|
+
"OPENAI_BASE_URL",
|
|
25
|
+
"OPENAI_ORG_ID",
|
|
26
|
+
"OPENAI_PROJECT"
|
|
27
|
+
];
|
|
28
|
+
var AgentRuntimeResolutionError = class extends Error {
|
|
29
|
+
};
|
|
30
|
+
var CODEX_PROTOCOL_EVENT_NAMES = {
|
|
31
|
+
turnStarted: "turn/started",
|
|
32
|
+
turnCompleted: "turn/completed",
|
|
33
|
+
turnFailed: "turn/failed",
|
|
34
|
+
turnCancelled: "turn/cancelled",
|
|
35
|
+
toolCallRequested: "dynamic_tool_call_request",
|
|
36
|
+
inputRequired: "item/tool/requestUserInput",
|
|
37
|
+
rateLimit: "turn/rate_limit",
|
|
38
|
+
messageDelta: "item/message/delta"
|
|
39
|
+
};
|
|
40
|
+
var CODEX_MESSAGE_DELTA_METHODS = /* @__PURE__ */ new Set([
|
|
41
|
+
CODEX_PROTOCOL_EVENT_NAMES.messageDelta,
|
|
42
|
+
"codex/event/agent_message_content_delta",
|
|
43
|
+
"codex/event/agent_message_delta",
|
|
44
|
+
"item/agentMessage/delta"
|
|
45
|
+
]);
|
|
46
|
+
var CODEX_TOKEN_USAGE_METHODS = /* @__PURE__ */ new Set([
|
|
47
|
+
"thread/tokenUsage/updated",
|
|
48
|
+
"total_token_usage",
|
|
49
|
+
"codex/event/token_count"
|
|
50
|
+
]);
|
|
51
|
+
function createGitHubGraphQLToolDefinition(config) {
|
|
52
|
+
const entry = createGitHubGraphQLMcpServerEntry(config);
|
|
53
|
+
return {
|
|
54
|
+
name: "github_graphql",
|
|
55
|
+
description: "Execute GitHub GraphQL queries for the active workspace so the agent can mutate project and issue state directly.",
|
|
56
|
+
command: entry.command,
|
|
57
|
+
args: entry.args,
|
|
58
|
+
env: entry.env,
|
|
59
|
+
inputSchema: {
|
|
60
|
+
type: "object",
|
|
61
|
+
properties: {
|
|
62
|
+
query: {
|
|
63
|
+
type: "string",
|
|
64
|
+
description: "GraphQL query or mutation document."
|
|
65
|
+
},
|
|
66
|
+
variables: {
|
|
67
|
+
type: "object",
|
|
68
|
+
description: "Variables for the GraphQL document."
|
|
69
|
+
},
|
|
70
|
+
operationName: {
|
|
71
|
+
type: "string",
|
|
72
|
+
description: "Optional GraphQL operation name."
|
|
73
|
+
}
|
|
74
|
+
},
|
|
75
|
+
required: ["query"],
|
|
76
|
+
additionalProperties: false
|
|
77
|
+
}
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
function asRecord(value) {
|
|
81
|
+
return value != null && typeof value === "object" ? value : {};
|
|
82
|
+
}
|
|
83
|
+
function hasOwn(record, key) {
|
|
84
|
+
return Object.prototype.hasOwnProperty.call(record, key);
|
|
85
|
+
}
|
|
86
|
+
function hasNestedRateLimitPayload(value) {
|
|
87
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
88
|
+
return false;
|
|
89
|
+
}
|
|
90
|
+
const record = value;
|
|
91
|
+
const directKeys = [
|
|
92
|
+
"limit",
|
|
93
|
+
"remaining",
|
|
94
|
+
"used",
|
|
95
|
+
"reset",
|
|
96
|
+
"resetAt",
|
|
97
|
+
"resets_at",
|
|
98
|
+
"reset_at"
|
|
99
|
+
];
|
|
100
|
+
if (directKeys.some((key) => hasOwn(record, key))) {
|
|
101
|
+
return true;
|
|
102
|
+
}
|
|
103
|
+
const preferredKeys = [
|
|
104
|
+
"rate_limits",
|
|
105
|
+
"rateLimits",
|
|
106
|
+
"rate_limit",
|
|
107
|
+
"rateLimit",
|
|
108
|
+
"result"
|
|
109
|
+
];
|
|
110
|
+
for (const key of preferredKeys) {
|
|
111
|
+
if (hasOwn(record, key) && hasNestedRateLimitPayload(record[key])) {
|
|
112
|
+
return true;
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
return false;
|
|
116
|
+
}
|
|
117
|
+
function getCodexObservabilityEventName(event) {
|
|
118
|
+
return event.payload.observabilityEvent;
|
|
119
|
+
}
|
|
120
|
+
function normalizeCodexRuntimeEvents(message) {
|
|
121
|
+
const method = typeof message.method === "string" ? message.method : void 0;
|
|
122
|
+
if (!method) {
|
|
123
|
+
return [];
|
|
124
|
+
}
|
|
125
|
+
const params = asRecord(message.params);
|
|
126
|
+
const events = [];
|
|
127
|
+
if (method === CODEX_PROTOCOL_EVENT_NAMES.turnStarted) {
|
|
128
|
+
events.push({
|
|
129
|
+
name: "agent.turnStarted",
|
|
130
|
+
payload: {
|
|
131
|
+
observabilityEvent: method,
|
|
132
|
+
params
|
|
133
|
+
}
|
|
134
|
+
});
|
|
135
|
+
return events;
|
|
136
|
+
}
|
|
137
|
+
if (method === CODEX_PROTOCOL_EVENT_NAMES.toolCallRequested) {
|
|
138
|
+
events.push({
|
|
139
|
+
name: "agent.toolCallRequested",
|
|
140
|
+
payload: {
|
|
141
|
+
observabilityEvent: method,
|
|
142
|
+
params,
|
|
143
|
+
callId: typeof params.callId === "string" ? params.callId : "",
|
|
144
|
+
toolName: typeof params.tool === "string" ? params.tool : "",
|
|
145
|
+
threadId: typeof params.threadId === "string" ? params.threadId : "",
|
|
146
|
+
turnId: typeof params.turnId === "string" ? params.turnId : "",
|
|
147
|
+
arguments: params.arguments
|
|
148
|
+
}
|
|
149
|
+
});
|
|
150
|
+
return events;
|
|
151
|
+
}
|
|
152
|
+
if (method === CODEX_PROTOCOL_EVENT_NAMES.inputRequired) {
|
|
153
|
+
events.push({
|
|
154
|
+
name: "agent.inputRequired",
|
|
155
|
+
payload: {
|
|
156
|
+
observabilityEvent: method,
|
|
157
|
+
params,
|
|
158
|
+
reason: buildAgentInputRequiredReason(params.prompt)
|
|
159
|
+
}
|
|
160
|
+
});
|
|
161
|
+
return events;
|
|
162
|
+
}
|
|
163
|
+
if (CODEX_TOKEN_USAGE_METHODS.has(method)) {
|
|
164
|
+
events.push({
|
|
165
|
+
name: "agent.tokenUsageUpdated",
|
|
166
|
+
payload: {
|
|
167
|
+
observabilityEvent: method,
|
|
168
|
+
params
|
|
169
|
+
}
|
|
170
|
+
});
|
|
171
|
+
return events;
|
|
172
|
+
}
|
|
173
|
+
if (CODEX_MESSAGE_DELTA_METHODS.has(method)) {
|
|
174
|
+
events.push({
|
|
175
|
+
name: "agent.messageDelta",
|
|
176
|
+
payload: {
|
|
177
|
+
observabilityEvent: method,
|
|
178
|
+
params,
|
|
179
|
+
delta: typeof params.delta === "string" ? params.delta : "",
|
|
180
|
+
itemId: typeof params.item_id === "string" ? params.item_id : ""
|
|
181
|
+
}
|
|
182
|
+
});
|
|
183
|
+
return events;
|
|
184
|
+
}
|
|
185
|
+
if (method === CODEX_PROTOCOL_EVENT_NAMES.rateLimit) {
|
|
186
|
+
events.push({
|
|
187
|
+
name: "agent.rateLimit",
|
|
188
|
+
payload: {
|
|
189
|
+
observabilityEvent: method,
|
|
190
|
+
params
|
|
191
|
+
}
|
|
192
|
+
});
|
|
193
|
+
return events;
|
|
194
|
+
}
|
|
195
|
+
if (method === CODEX_PROTOCOL_EVENT_NAMES.turnCompleted) {
|
|
196
|
+
if (hasOwn(params, "usage")) {
|
|
197
|
+
events.push({
|
|
198
|
+
name: "agent.tokenUsageUpdated",
|
|
199
|
+
payload: {
|
|
200
|
+
observabilityEvent: method,
|
|
201
|
+
params: asRecord(params.usage),
|
|
202
|
+
suppressUpdate: true
|
|
203
|
+
}
|
|
204
|
+
});
|
|
205
|
+
}
|
|
206
|
+
if (hasNestedRateLimitPayload(params)) {
|
|
207
|
+
events.push({
|
|
208
|
+
name: "agent.rateLimit",
|
|
209
|
+
payload: {
|
|
210
|
+
observabilityEvent: method,
|
|
211
|
+
params,
|
|
212
|
+
suppressUpdate: true
|
|
213
|
+
}
|
|
214
|
+
});
|
|
215
|
+
}
|
|
216
|
+
events.push({
|
|
217
|
+
name: "agent.turnCompleted",
|
|
218
|
+
payload: {
|
|
219
|
+
observabilityEvent: method,
|
|
220
|
+
params,
|
|
221
|
+
inputRequired: params.inputRequired === true
|
|
222
|
+
}
|
|
223
|
+
});
|
|
224
|
+
return events;
|
|
225
|
+
}
|
|
226
|
+
if (method === CODEX_PROTOCOL_EVENT_NAMES.turnFailed) {
|
|
227
|
+
events.push({
|
|
228
|
+
name: "agent.turnFailed",
|
|
229
|
+
payload: {
|
|
230
|
+
observabilityEvent: method,
|
|
231
|
+
params
|
|
232
|
+
}
|
|
233
|
+
});
|
|
234
|
+
return events;
|
|
235
|
+
}
|
|
236
|
+
if (method === CODEX_PROTOCOL_EVENT_NAMES.turnCancelled) {
|
|
237
|
+
events.push({
|
|
238
|
+
name: "agent.turnCancelled",
|
|
239
|
+
payload: {
|
|
240
|
+
observabilityEvent: method,
|
|
241
|
+
params
|
|
242
|
+
}
|
|
243
|
+
});
|
|
244
|
+
return events;
|
|
245
|
+
}
|
|
246
|
+
if (method === "error") {
|
|
247
|
+
events.push({
|
|
248
|
+
name: "agent.error",
|
|
249
|
+
payload: {
|
|
250
|
+
observabilityEvent: method,
|
|
251
|
+
params,
|
|
252
|
+
error: JSON.stringify(params)
|
|
253
|
+
}
|
|
254
|
+
});
|
|
255
|
+
return events;
|
|
256
|
+
}
|
|
257
|
+
return events;
|
|
258
|
+
}
|
|
259
|
+
function resolveStagedCodexHome(workingDirectory) {
|
|
260
|
+
return join(workingDirectory, STAGED_CODEX_HOME_DIRNAME);
|
|
261
|
+
}
|
|
262
|
+
function resolvePreparedAgentEnvironment(workingDirectory, env) {
|
|
263
|
+
const preparedEnv = Object.fromEntries(
|
|
264
|
+
DIRECT_AGENT_ENV_KEYS.flatMap((key) => {
|
|
265
|
+
const value = env?.[key];
|
|
266
|
+
return typeof value === "string" && value.length > 0 ? [[key, value]] : [];
|
|
267
|
+
})
|
|
268
|
+
);
|
|
269
|
+
return {
|
|
270
|
+
...preparedEnv,
|
|
271
|
+
CODEX_HOME: resolveStagedCodexHome(workingDirectory)
|
|
272
|
+
};
|
|
273
|
+
}
|
|
274
|
+
function buildCodexRuntimePlan(config) {
|
|
275
|
+
const tool = createGitHubGraphQLToolDefinition(config);
|
|
276
|
+
const gitCredentialHelper = createGitCredentialHelperEnvironment(config);
|
|
277
|
+
const shellCmd = (() => {
|
|
278
|
+
const cmd = config.agentCommand ?? "codex app-server";
|
|
279
|
+
return cmd.startsWith("bash -lc ") ? cmd.slice("bash -lc ".length) : cmd;
|
|
280
|
+
})();
|
|
281
|
+
const agentEnv = resolvePreparedAgentEnvironment(
|
|
282
|
+
config.workingDirectory,
|
|
283
|
+
config.agentEnv
|
|
284
|
+
);
|
|
285
|
+
return {
|
|
286
|
+
cwd: config.workingDirectory,
|
|
287
|
+
command: "bash",
|
|
288
|
+
args: ["-lc", shellCmd],
|
|
289
|
+
env: {
|
|
290
|
+
...process.env,
|
|
291
|
+
...config.extraEnv,
|
|
292
|
+
...config.agentEnv,
|
|
293
|
+
CODEX_PROJECT_ID: config.projectId,
|
|
294
|
+
GITHUB_PROJECT_ID: config.githubProjectId ?? "",
|
|
295
|
+
GITHUB_GRAPHQL_TOOL_NAME: tool.name,
|
|
296
|
+
GITHUB_GRAPHQL_TOOL_COMMAND: [tool.command, ...tool.args].join(" "),
|
|
297
|
+
...agentEnv,
|
|
298
|
+
...gitCredentialHelper,
|
|
299
|
+
...tool.env
|
|
300
|
+
},
|
|
301
|
+
tools: [tool]
|
|
302
|
+
};
|
|
303
|
+
}
|
|
304
|
+
function launchCodexAppServer(plan, spawnImpl = spawn) {
|
|
305
|
+
return spawnImpl(plan.command, plan.args, {
|
|
306
|
+
cwd: plan.cwd,
|
|
307
|
+
env: plan.env,
|
|
308
|
+
stdio: "pipe"
|
|
309
|
+
});
|
|
310
|
+
}
|
|
311
|
+
var CodexRuntimeAdapter = class {
|
|
312
|
+
constructor(config, dependencies = {}) {
|
|
313
|
+
this.config = config;
|
|
314
|
+
this.dependencies = dependencies;
|
|
315
|
+
}
|
|
316
|
+
// Event emission is intentionally deferred until the worker-owned loop is
|
|
317
|
+
// neutralized in #4. Until then, keep handler registration compatible.
|
|
318
|
+
handlers = /* @__PURE__ */ new Set();
|
|
319
|
+
plan = null;
|
|
320
|
+
child = null;
|
|
321
|
+
async prepare(_context) {
|
|
322
|
+
if (this.plan) {
|
|
323
|
+
return;
|
|
324
|
+
}
|
|
325
|
+
const agentEnv = await resolveAgentRuntimeEnvironment(
|
|
326
|
+
this.config,
|
|
327
|
+
this.dependencies,
|
|
328
|
+
this
|
|
329
|
+
);
|
|
330
|
+
await stageCodexHome(this.config, this.dependencies);
|
|
331
|
+
this.plan = buildCodexRuntimePlan({
|
|
332
|
+
...this.config,
|
|
333
|
+
agentEnv
|
|
334
|
+
});
|
|
335
|
+
}
|
|
336
|
+
async spawnTurn(_input) {
|
|
337
|
+
if (!this.plan) {
|
|
338
|
+
await this.prepare();
|
|
339
|
+
}
|
|
340
|
+
if (!this.plan) {
|
|
341
|
+
throw new AgentRuntimeResolutionError(
|
|
342
|
+
"Codex runtime plan was not prepared before spawnTurn."
|
|
343
|
+
);
|
|
344
|
+
}
|
|
345
|
+
if (!hasRunningChild(this.child)) {
|
|
346
|
+
this.child = launchCodexAppServer(
|
|
347
|
+
this.plan,
|
|
348
|
+
this.dependencies.spawnImpl ?? spawn
|
|
349
|
+
);
|
|
350
|
+
}
|
|
351
|
+
return {
|
|
352
|
+
plan: this.plan,
|
|
353
|
+
child: this.child
|
|
354
|
+
};
|
|
355
|
+
}
|
|
356
|
+
onEvent(handler) {
|
|
357
|
+
this.handlers.add(handler);
|
|
358
|
+
return () => {
|
|
359
|
+
this.handlers.delete(handler);
|
|
360
|
+
};
|
|
361
|
+
}
|
|
362
|
+
resolveCredentials(brokerResponse) {
|
|
363
|
+
return resolvePreparedAgentEnvironment(
|
|
364
|
+
this.config.workingDirectory,
|
|
365
|
+
brokerResponse.env
|
|
366
|
+
);
|
|
367
|
+
}
|
|
368
|
+
async shutdown() {
|
|
369
|
+
terminateChildProcess(this.child);
|
|
370
|
+
this.child = null;
|
|
371
|
+
this.handlers.clear();
|
|
372
|
+
}
|
|
373
|
+
async cancel(_reason) {
|
|
374
|
+
terminateChildProcess(this.child);
|
|
375
|
+
this.child = null;
|
|
376
|
+
this.handlers.clear();
|
|
377
|
+
}
|
|
378
|
+
getPreparedPlan() {
|
|
379
|
+
return this.plan;
|
|
380
|
+
}
|
|
381
|
+
};
|
|
382
|
+
function createCodexRuntimeAdapter(config, dependencies = {}) {
|
|
383
|
+
return new CodexRuntimeAdapter(config, dependencies);
|
|
384
|
+
}
|
|
385
|
+
async function prepareCodexRuntimePlan(config, dependencies = {}) {
|
|
386
|
+
const adapter = createCodexRuntimeAdapter(config, dependencies);
|
|
387
|
+
await adapter.prepare();
|
|
388
|
+
const plan = adapter.getPreparedPlan();
|
|
389
|
+
if (!plan) {
|
|
390
|
+
throw new AgentRuntimeResolutionError(
|
|
391
|
+
"Codex runtime plan was not prepared."
|
|
392
|
+
);
|
|
393
|
+
}
|
|
394
|
+
return plan;
|
|
395
|
+
}
|
|
396
|
+
function createGitCredentialHelperEnvironment(config) {
|
|
397
|
+
return {
|
|
398
|
+
GITHUB_GIT_HOST: DEFAULT_GITHUB_GIT_HOST,
|
|
399
|
+
GITHUB_GIT_USERNAME: DEFAULT_GITHUB_GIT_USERNAME,
|
|
400
|
+
GIT_TERMINAL_PROMPT: "0",
|
|
401
|
+
GIT_CONFIG_COUNT: "1",
|
|
402
|
+
GIT_CONFIG_KEY_0: "credential.helper",
|
|
403
|
+
GIT_CONFIG_VALUE_0: `!node ${fileURLToPath(
|
|
404
|
+
new URL("./git-credential-helper.js", import.meta.url)
|
|
405
|
+
)}`,
|
|
406
|
+
...config.githubToken ? {
|
|
407
|
+
GITHUB_GRAPHQL_TOKEN: config.githubToken
|
|
408
|
+
} : {},
|
|
409
|
+
...config.githubTokenBrokerUrl ? {
|
|
410
|
+
GITHUB_TOKEN_BROKER_URL: config.githubTokenBrokerUrl
|
|
411
|
+
} : {},
|
|
412
|
+
...config.githubTokenBrokerSecret ? {
|
|
413
|
+
GITHUB_TOKEN_BROKER_SECRET: config.githubTokenBrokerSecret
|
|
414
|
+
} : {},
|
|
415
|
+
...config.githubTokenCachePath ? {
|
|
416
|
+
GITHUB_TOKEN_CACHE_PATH: config.githubTokenCachePath
|
|
417
|
+
} : {}
|
|
418
|
+
};
|
|
419
|
+
}
|
|
420
|
+
async function resolveAgentRuntimeEnvironment(config, dependencies = {}, adapter) {
|
|
421
|
+
if (config.agentEnv) {
|
|
422
|
+
return resolveRuntimeCredentials(config, { env: config.agentEnv }, adapter);
|
|
423
|
+
}
|
|
424
|
+
if (!config.agentCredentialBrokerUrl || !config.agentCredentialBrokerSecret) {
|
|
425
|
+
return resolvePreparedAgentEnvironment(config.workingDirectory);
|
|
426
|
+
}
|
|
427
|
+
const now = dependencies.now ?? /* @__PURE__ */ new Date();
|
|
428
|
+
const readFileImpl = dependencies.readFileImpl ?? readFile;
|
|
429
|
+
const cachedCredentials = config.agentCredentialCachePath ? await readAgentCredentialCache(config.agentCredentialCachePath, readFileImpl) : null;
|
|
430
|
+
if (cachedCredentials && shouldReuseAgentCredentialCache(cachedCredentials, now)) {
|
|
431
|
+
return resolveRuntimeCredentials(config, cachedCredentials, adapter);
|
|
432
|
+
}
|
|
433
|
+
const fetchImpl = dependencies.fetchImpl ?? fetch;
|
|
434
|
+
const response = await fetchImpl(config.agentCredentialBrokerUrl, {
|
|
435
|
+
method: "POST",
|
|
436
|
+
headers: {
|
|
437
|
+
accept: "application/json",
|
|
438
|
+
authorization: `Bearer ${config.agentCredentialBrokerSecret}`
|
|
439
|
+
}
|
|
440
|
+
});
|
|
441
|
+
const payload = await response.json();
|
|
442
|
+
const resolvedEnv = payload.env && response.ok ? adapter ? adapter.resolveCredentials({
|
|
443
|
+
env: payload.env,
|
|
444
|
+
expires_at: payload.expires_at
|
|
445
|
+
}) : resolvePreparedAgentEnvironment(config.workingDirectory, payload.env) : null;
|
|
446
|
+
if (!response.ok || !payload.env || Object.keys(payload.env).length === 0 || !resolvedEnv) {
|
|
447
|
+
throw new AgentRuntimeResolutionError(
|
|
448
|
+
payload.error ?? `Agent credential broker request failed with status ${response.status}.`
|
|
449
|
+
);
|
|
450
|
+
}
|
|
451
|
+
if (config.agentCredentialCachePath) {
|
|
452
|
+
const writeFileImpl = dependencies.writeFileImpl ?? writeFile;
|
|
453
|
+
await writeAgentCredentialCache(
|
|
454
|
+
config.agentCredentialCachePath,
|
|
455
|
+
payload,
|
|
456
|
+
writeFileImpl,
|
|
457
|
+
now
|
|
458
|
+
);
|
|
459
|
+
}
|
|
460
|
+
return resolvedEnv;
|
|
461
|
+
}
|
|
462
|
+
function resolveRuntimeCredentials(config, brokerResponse, adapter) {
|
|
463
|
+
return adapter ? adapter.resolveCredentials(brokerResponse) : resolvePreparedAgentEnvironment(config.workingDirectory, brokerResponse.env);
|
|
464
|
+
}
|
|
465
|
+
async function stageCodexHome(config, dependencies = {}) {
|
|
466
|
+
const codexHomeDir = resolveStagedCodexHome(config.workingDirectory);
|
|
467
|
+
const mkdirImpl = dependencies.mkdirImpl ?? mkdir;
|
|
468
|
+
await mkdirImpl(codexHomeDir, { recursive: true });
|
|
469
|
+
const writeFileImpl = dependencies.writeFileImpl ?? writeFile;
|
|
470
|
+
await writeFileImpl(
|
|
471
|
+
join(codexHomeDir, "config.toml"),
|
|
472
|
+
"# Isolated agent config \u2014 no personal MCP servers\n",
|
|
473
|
+
"utf8"
|
|
474
|
+
);
|
|
475
|
+
const realCodexHome = process.env.CODEX_HOME ?? join(homedir(), ".codex");
|
|
476
|
+
const copyFileImpl = dependencies.copyFileImpl ?? copyFile;
|
|
477
|
+
try {
|
|
478
|
+
await copyFileImpl(
|
|
479
|
+
join(realCodexHome, "auth.json"),
|
|
480
|
+
join(codexHomeDir, "auth.json")
|
|
481
|
+
);
|
|
482
|
+
} catch {
|
|
483
|
+
}
|
|
484
|
+
}
|
|
485
|
+
function hasRunningChild(child) {
|
|
486
|
+
return child !== null && child.exitCode === null && child.signalCode === null;
|
|
487
|
+
}
|
|
488
|
+
function terminateChildProcess(child) {
|
|
489
|
+
if (!hasRunningChild(child) || !child.pid) {
|
|
490
|
+
return;
|
|
491
|
+
}
|
|
492
|
+
try {
|
|
493
|
+
child.kill("SIGTERM");
|
|
494
|
+
} catch {
|
|
495
|
+
}
|
|
496
|
+
}
|
|
497
|
+
|
|
498
|
+
// ../runtime-codex/src/launcher.ts
|
|
499
|
+
import { dirname, resolve } from "path";
|
|
500
|
+
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
501
|
+
var LocalRuntimeLauncherError = class extends Error {
|
|
502
|
+
};
|
|
503
|
+
function resolveLocalRuntimeLaunchConfig(env = process.env) {
|
|
504
|
+
const projectId = env.PROJECT_ID ?? env.CODEX_PROJECT_ID;
|
|
505
|
+
const workingDirectory = env.WORKING_DIRECTORY;
|
|
506
|
+
if (!projectId) {
|
|
507
|
+
throw new LocalRuntimeLauncherError(
|
|
508
|
+
"PROJECT_ID or CODEX_PROJECT_ID is required."
|
|
509
|
+
);
|
|
510
|
+
}
|
|
511
|
+
if (!workingDirectory) {
|
|
512
|
+
throw new LocalRuntimeLauncherError("WORKING_DIRECTORY is required.");
|
|
513
|
+
}
|
|
514
|
+
return {
|
|
515
|
+
projectId,
|
|
516
|
+
workingDirectory,
|
|
517
|
+
githubToken: env.GITHUB_GRAPHQL_TOKEN,
|
|
518
|
+
githubTokenBrokerUrl: env.GITHUB_TOKEN_BROKER_URL,
|
|
519
|
+
githubTokenBrokerSecret: env.GITHUB_TOKEN_BROKER_SECRET,
|
|
520
|
+
githubTokenCachePath: env.GITHUB_TOKEN_CACHE_PATH,
|
|
521
|
+
agentEnv: readDirectAgentEnvironment(env),
|
|
522
|
+
agentCredentialBrokerUrl: env.AGENT_CREDENTIAL_BROKER_URL,
|
|
523
|
+
agentCredentialBrokerSecret: env.AGENT_CREDENTIAL_BROKER_SECRET,
|
|
524
|
+
agentCredentialCachePath: env.AGENT_CREDENTIAL_CACHE_PATH,
|
|
525
|
+
githubProjectId: env.GITHUB_PROJECT_ID,
|
|
526
|
+
githubGraphqlApiUrl: env.GITHUB_GRAPHQL_API_URL,
|
|
527
|
+
agentCommand: env.SYMPHONY_AGENT_COMMAND
|
|
528
|
+
};
|
|
529
|
+
}
|
|
530
|
+
async function runLocalRuntimeLauncher(env = process.env) {
|
|
531
|
+
const launcherEnv = loadLauncherEnvironment(env);
|
|
532
|
+
const config = resolveLocalRuntimeLaunchConfig(launcherEnv);
|
|
533
|
+
const plan = await prepareCodexRuntimePlan(config);
|
|
534
|
+
emitLaunchSummary(config);
|
|
535
|
+
const child = launchCodexAppServer(plan);
|
|
536
|
+
process.stdout.write(
|
|
537
|
+
`[worker] codex app-server started (pid: ${child.pid ?? "unknown"})
|
|
538
|
+
`
|
|
539
|
+
);
|
|
540
|
+
child.stdout?.pipe(process.stdout);
|
|
541
|
+
child.stderr?.pipe(process.stderr);
|
|
542
|
+
return await waitForChildProcess(child);
|
|
543
|
+
}
|
|
544
|
+
function loadLauncherEnvironment(env = process.env, cwd = process.cwd()) {
|
|
545
|
+
const mergedEnv = {
|
|
546
|
+
...readEnvFile(
|
|
547
|
+
resolve(dirname(fileURLToPath2(import.meta.url)), "..", ".env")
|
|
548
|
+
),
|
|
549
|
+
...readEnvFile(resolve(cwd, ".env")),
|
|
550
|
+
...env
|
|
551
|
+
};
|
|
552
|
+
return mergedEnv;
|
|
553
|
+
}
|
|
554
|
+
function readDirectAgentEnvironment(env) {
|
|
555
|
+
const agentEnv = extractEnvForCodex(env);
|
|
556
|
+
return Object.keys(agentEnv).length ? agentEnv : void 0;
|
|
557
|
+
}
|
|
558
|
+
function waitForChildProcess(child) {
|
|
559
|
+
return new Promise((resolve2, reject) => {
|
|
560
|
+
child.once("error", reject);
|
|
561
|
+
child.once("exit", (code, signal) => {
|
|
562
|
+
if (signal) {
|
|
563
|
+
reject(
|
|
564
|
+
new LocalRuntimeLauncherError(`codex app-server exited on ${signal}.`)
|
|
565
|
+
);
|
|
566
|
+
return;
|
|
567
|
+
}
|
|
568
|
+
resolve2(code ?? 0);
|
|
569
|
+
});
|
|
570
|
+
});
|
|
571
|
+
}
|
|
572
|
+
async function main() {
|
|
573
|
+
const exitCode = await runLocalRuntimeLauncher(process.env);
|
|
574
|
+
process.exitCode = exitCode;
|
|
575
|
+
}
|
|
576
|
+
if (import.meta.url === new URL(process.argv[1] ?? "", "file:").href) {
|
|
577
|
+
main().catch((error) => {
|
|
578
|
+
const message = error instanceof Error ? error.message : "Unknown error";
|
|
579
|
+
process.stderr.write(`${message}
|
|
580
|
+
`);
|
|
581
|
+
process.exitCode = 1;
|
|
582
|
+
});
|
|
583
|
+
}
|
|
584
|
+
function emitLaunchSummary(config) {
|
|
585
|
+
const githubAuthMode = config.githubToken ? "direct token" : config.githubTokenBrokerUrl && config.githubTokenBrokerSecret ? "broker" : "missing";
|
|
586
|
+
const agentAuthMode = config.agentEnv?.OPENAI_API_KEY ? "direct env" : config.agentCredentialBrokerUrl && config.agentCredentialBrokerSecret ? "broker" : "local codex auth or inherited environment";
|
|
587
|
+
process.stdout.write(
|
|
588
|
+
[
|
|
589
|
+
"[worker] starting local codex runtime",
|
|
590
|
+
`[worker] project: ${config.projectId}`,
|
|
591
|
+
`[worker] cwd: ${config.workingDirectory}`,
|
|
592
|
+
`[worker] github project: ${config.githubProjectId ?? "(unset)"}`,
|
|
593
|
+
`[worker] github auth: ${githubAuthMode}`,
|
|
594
|
+
`[worker] agent auth: ${agentAuthMode}`,
|
|
595
|
+
"[worker] note: codex app-server does not proactively read GitHub issues.",
|
|
596
|
+
"[worker] note: it waits for a client request or tool invocation."
|
|
597
|
+
].join("\n") + "\n"
|
|
598
|
+
);
|
|
599
|
+
}
|
|
600
|
+
|
|
601
|
+
// ../runtime-codex/src/git-credential-helper.ts
|
|
602
|
+
var DEFAULT_GITHUB_GIT_HOST2 = "github.com";
|
|
603
|
+
var DEFAULT_GITHUB_GIT_USERNAME2 = "x-access-token";
|
|
604
|
+
async function resolveGitCredential(request, config, fetchImpl = fetch) {
|
|
605
|
+
const requestHost = request.host?.trim();
|
|
606
|
+
const requestProtocol = request.protocol?.trim();
|
|
607
|
+
if (!requestHost || requestProtocol && requestProtocol !== "https") {
|
|
608
|
+
return "";
|
|
609
|
+
}
|
|
610
|
+
const expectedHost = normalizeGitHost(
|
|
611
|
+
config.gitHost ?? DEFAULT_GITHUB_GIT_HOST2
|
|
612
|
+
);
|
|
613
|
+
if (normalizeGitHost(requestHost) !== expectedHost) {
|
|
614
|
+
return "";
|
|
615
|
+
}
|
|
616
|
+
const token = await resolveGitHubGraphQLToken(config, {
|
|
617
|
+
fetchImpl
|
|
618
|
+
});
|
|
619
|
+
return formatGitCredentialResponse({
|
|
620
|
+
protocol: requestProtocol || "https",
|
|
621
|
+
host: requestHost,
|
|
622
|
+
username: config.gitUsername ?? DEFAULT_GITHUB_GIT_USERNAME2,
|
|
623
|
+
password: token
|
|
624
|
+
});
|
|
625
|
+
}
|
|
626
|
+
function parseGitCredentialRequest(rawInput) {
|
|
627
|
+
return rawInput.split("\n").map((line) => line.trim()).filter(Boolean).reduce((request, line) => {
|
|
628
|
+
const separatorIndex = line.indexOf("=");
|
|
629
|
+
if (separatorIndex === -1) {
|
|
630
|
+
return request;
|
|
631
|
+
}
|
|
632
|
+
const key = line.slice(0, separatorIndex);
|
|
633
|
+
const value = line.slice(separatorIndex + 1);
|
|
634
|
+
request[key] = value;
|
|
635
|
+
return request;
|
|
636
|
+
}, {});
|
|
637
|
+
}
|
|
638
|
+
function formatGitCredentialResponse(value) {
|
|
639
|
+
return `${Object.entries(value).map(([key, entry]) => `${key}=${entry}`).join("\n")}
|
|
640
|
+
|
|
641
|
+
`;
|
|
642
|
+
}
|
|
643
|
+
async function readStdin() {
|
|
644
|
+
const chunks = [];
|
|
645
|
+
for await (const chunk of process.stdin) {
|
|
646
|
+
chunks.push(typeof chunk === "string" ? Buffer.from(chunk) : chunk);
|
|
647
|
+
}
|
|
648
|
+
return Buffer.concat(chunks).toString("utf8");
|
|
649
|
+
}
|
|
650
|
+
async function main2() {
|
|
651
|
+
const request = parseGitCredentialRequest(await readStdin());
|
|
652
|
+
const response = await resolveGitCredential(request, {
|
|
653
|
+
token: process.env.GITHUB_GRAPHQL_TOKEN,
|
|
654
|
+
tokenBrokerUrl: process.env.GITHUB_TOKEN_BROKER_URL,
|
|
655
|
+
tokenBrokerSecret: process.env.GITHUB_TOKEN_BROKER_SECRET,
|
|
656
|
+
tokenCachePath: process.env.GITHUB_TOKEN_CACHE_PATH,
|
|
657
|
+
gitHost: process.env.GITHUB_GIT_HOST,
|
|
658
|
+
gitUsername: process.env.GITHUB_GIT_USERNAME
|
|
659
|
+
});
|
|
660
|
+
process.stdout.write(response);
|
|
661
|
+
}
|
|
662
|
+
if (import.meta.url === new URL(process.argv[1] ?? "", "file:").href) {
|
|
663
|
+
main2().catch((error) => {
|
|
664
|
+
const message = error instanceof Error ? error.message : "Unknown error";
|
|
665
|
+
process.stderr.write(`${message}
|
|
666
|
+
`);
|
|
667
|
+
process.exitCode = 1;
|
|
668
|
+
});
|
|
669
|
+
}
|
|
670
|
+
function normalizeGitHost(host) {
|
|
671
|
+
return host.trim().toLowerCase();
|
|
672
|
+
}
|
|
673
|
+
|
|
674
|
+
// ../runtime-codex/src/convergence-detection.ts
|
|
675
|
+
import { spawnSync } from "child_process";
|
|
676
|
+
|
|
677
|
+
export {
|
|
678
|
+
getCodexObservabilityEventName,
|
|
679
|
+
normalizeCodexRuntimeEvents,
|
|
680
|
+
launchCodexAppServer,
|
|
681
|
+
prepareCodexRuntimePlan,
|
|
682
|
+
resolveLocalRuntimeLaunchConfig,
|
|
683
|
+
loadLauncherEnvironment
|
|
684
|
+
};
|
|
@@ -51,6 +51,14 @@ function showCursor() {
|
|
|
51
51
|
return "\x1B[?25h";
|
|
52
52
|
}
|
|
53
53
|
|
|
54
|
+
// src/format/repository.ts
|
|
55
|
+
function formatRepositoryDisplay(snapshot, fallback = "repository") {
|
|
56
|
+
if (snapshot.repository) {
|
|
57
|
+
return `${snapshot.repository.owner}/${snapshot.repository.name}`;
|
|
58
|
+
}
|
|
59
|
+
return snapshot.slug ?? fallback;
|
|
60
|
+
}
|
|
61
|
+
|
|
54
62
|
export {
|
|
55
63
|
bold,
|
|
56
64
|
dim,
|
|
@@ -64,5 +72,6 @@ export {
|
|
|
64
72
|
setNoColor,
|
|
65
73
|
clearScreen,
|
|
66
74
|
hideCursor,
|
|
67
|
-
showCursor
|
|
75
|
+
showCursor,
|
|
76
|
+
formatRepositoryDisplay
|
|
68
77
|
};
|