@nairon-ai/aegis 0.4.9 → 0.5.0

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.
Files changed (35) hide show
  1. package/.flue/app.ts +35 -3
  2. package/README.md +16 -10
  3. package/dist-node/cli/commands/deploy.js +2 -0
  4. package/dist-node/cli/commands/deploy.js.map +1 -1
  5. package/dist-node/cli/commands/disconnect.d.ts.map +1 -1
  6. package/dist-node/cli/commands/disconnect.js +18 -4
  7. package/dist-node/cli/commands/disconnect.js.map +1 -1
  8. package/dist-node/cli/commands/init.d.ts.map +1 -1
  9. package/dist-node/cli/commands/init.js +5 -2
  10. package/dist-node/cli/commands/init.js.map +1 -1
  11. package/dist-node/cli/commands/setup.d.ts.map +1 -1
  12. package/dist-node/cli/commands/setup.js +260 -46
  13. package/dist-node/cli/commands/setup.js.map +1 -1
  14. package/dist-node/cli/state.d.ts.map +1 -1
  15. package/dist-node/cli/state.js +8 -0
  16. package/dist-node/cli/state.js.map +1 -1
  17. package/dist-node/shared/config.d.ts.map +1 -1
  18. package/dist-node/shared/config.js +4 -1
  19. package/dist-node/shared/config.js.map +1 -1
  20. package/dist-node/shared/constants.d.ts +36 -2
  21. package/dist-node/shared/constants.d.ts.map +1 -1
  22. package/dist-node/shared/constants.js +47 -2
  23. package/dist-node/shared/constants.js.map +1 -1
  24. package/dist-node/shared/types.d.ts +6 -0
  25. package/dist-node/shared/types.d.ts.map +1 -1
  26. package/docs/SETUP.md +19 -10
  27. package/package.json +2 -1
  28. package/src/cli/commands/deploy.ts +2 -0
  29. package/src/cli/commands/disconnect.ts +17 -4
  30. package/src/cli/commands/init.ts +5 -2
  31. package/src/cli/commands/setup.ts +304 -65
  32. package/src/cli/state.ts +8 -0
  33. package/src/shared/config.ts +4 -0
  34. package/src/shared/constants.ts +47 -2
  35. package/src/shared/types.ts +7 -0
package/.flue/app.ts CHANGED
@@ -1,4 +1,5 @@
1
- import { flue } from "@flue/sdk/app";
1
+ import { configureProvider, flue } from "@flue/sdk/app";
2
+ import { refreshOpenAICodexToken } from "@mariozechner/pi-ai/oauth";
2
3
  import { createAegisApp, scheduledPickup } from "../src/server/app.js";
3
4
  import type { Bindings } from "../src/shared/types.js";
4
5
 
@@ -6,11 +7,42 @@ const app = createAegisApp();
6
7
  const flueApp = flue();
7
8
 
8
9
  export default {
9
- fetch(request: Request, env?: Bindings, ctx?: ExecutionContext) {
10
+ async fetch(request: Request, env?: Bindings, ctx?: ExecutionContext) {
11
+ await configureAgentProviders(env);
10
12
  if (new URL(request.url).pathname.startsWith("/agents/")) {
11
13
  return flueApp.fetch(request, env, ctx);
12
14
  }
13
15
  return app.fetch(request, env, ctx);
14
16
  },
15
- scheduled: scheduledPickup,
17
+ async scheduled(controller: ScheduledController, env: Bindings, ctx: ExecutionContext) {
18
+ await configureAgentProviders(env);
19
+ return scheduledPickup(controller, env, ctx);
20
+ },
16
21
  };
22
+
23
+ async function configureAgentProviders(env?: Bindings): Promise<void> {
24
+ if (env?.AGENT_AUTH_METHOD !== "codex-account" || !env.CODEX_OAUTH_CREDENTIALS_B64) return;
25
+ const credentials = decodeCodexCredentials(env.CODEX_OAUTH_CREDENTIALS_B64);
26
+ const refreshed =
27
+ typeof credentials.expires === "number" && credentials.expires < Date.now() + 5 * 60_000
28
+ ? await refreshOpenAICodexToken(credentials.refresh)
29
+ : credentials;
30
+ configureProvider("openai-codex", { apiKey: refreshed.access });
31
+ }
32
+
33
+ function decodeCodexCredentials(value: string): {
34
+ access: string;
35
+ refresh: string;
36
+ expires: number;
37
+ } {
38
+ const json = new TextDecoder().decode(Uint8Array.from(atob(value), (char) => char.charCodeAt(0)));
39
+ const parsed = JSON.parse(json) as { access?: string; refresh?: string; expires?: number };
40
+ if (!parsed.access || !parsed.refresh || typeof parsed.expires !== "number") {
41
+ throw new Error("Invalid Codex account credentials. Rerun `aegis setup`.");
42
+ }
43
+ return {
44
+ access: parsed.access,
45
+ refresh: parsed.refresh,
46
+ expires: parsed.expires,
47
+ };
48
+ }
package/README.md CHANGED
@@ -51,10 +51,11 @@ No Cloudflare required for this part.
51
51
  2. Run `npx --yes @nairon-ai/aegis@latest init`.
52
52
  3. Run `npx --yes @nairon-ai/aegis@latest setup`.
53
53
  4. Choose `One-click GitHub App` unless you already know how to create a GitHub token.
54
- 5. Choose `plan-first` and `minimal` for the first test.
55
- 6. Add `bug` and `ready to implement` labels to the monitored GitHub repo.
56
- 7. Create a test bug issue with both labels.
57
- 8. Run `npx --yes @nairon-ai/aegis@latest pickup --dry-run`.
54
+ 5. Choose `Codex account / ChatGPT login` or `OpenAI API key`, then choose the model.
55
+ 6. Choose `plan-first` and `minimal` for the first test.
56
+ 7. Add `bug` and `ready to implement` labels to the monitored GitHub repo.
57
+ 8. Create a test bug issue with both labels.
58
+ 9. Run `npx --yes @nairon-ai/aegis@latest pickup --dry-run`.
58
59
 
59
60
  Good first result:
60
61
 
@@ -78,6 +79,10 @@ GitHub App credentials are saved in `.aegis/.env` and backed up for your Mac use
78
79
 
79
80
  If you connect Linear, Aegis fetches your Linear teams after you paste the API key and lets you choose by name, for example `Engineering (ENG)`. You do not need to hunt for Linear UUIDs manually.
80
81
 
82
+ For model auth, Aegis asks account first, then model. `Codex account / ChatGPT login` uses `openai-codex/...` models and stores OAuth credentials for your self-hosted Worker. `OpenAI API key` uses `openai/...` models and normal API billing.
83
+
84
+ Setup reruns check each completed step first. Existing Codex credentials, API keys, webhook secrets, Linear team, Telegram config, production context, model choice, and Worker URL are reused unless you choose to reconfigure that step.
85
+
81
86
  ### Deployed AFK Mode
82
87
 
83
88
  Deploy only after the local dry-run works.
@@ -134,7 +139,7 @@ Cloudflare Sandbox is currently available on Workers Paid and uses Docker during
134
139
  - Docker running locally for Cloudflare Sandbox image deploy
135
140
  - Cloudflare account and Workers Paid for deployed mode
136
141
  - GitHub App or GitHub token with Contents, Issues, and Pull Requests read/write access
137
- - OpenAI API key for the default `openai/gpt-5.5` model, or another Flue-supported model provider key
142
+ - Codex account login for the default `openai-codex/gpt-5.5` model, or an OpenAI API key for `openai/...` models
138
143
  - Optional: Linear API key
139
144
  - Optional: Telegram bot
140
145
  - Optional: read-only production database URL
@@ -180,11 +185,12 @@ npx --yes @nairon-ai/aegis@latest disconnect
180
185
  To fully stop using Aegis:
181
186
 
182
187
  1. Delete the Cloudflare Worker if deployed: `npx wrangler delete aegis-worker`.
183
- 2. Uninstall the Aegis GitHub App from the repo, or revoke the GitHub token.
184
- 3. Delete Aegis webhooks from GitHub, Linear, and Telegram if configured.
185
- 4. Remove local config: `rm -rf .aegis`.
186
- 5. Remove cached GitHub App credentials if you used the app flow: `rm -f ~/.aegis/github-apps/YOUR-ORG-YOUR-REPO.env`.
187
- 6. Optionally remove Aegis-only labels: `aegis:in-progress`, `aegis:needs-info`, `aegis:blocked`, `aegis:pr-opened`.
188
+ 2. Revoke Codex account OAuth access or revoke the OpenAI API key, depending on model auth.
189
+ 3. Uninstall the Aegis GitHub App from the repo, or revoke the GitHub token.
190
+ 4. Delete Aegis webhooks from GitHub, Linear, and Telegram if configured.
191
+ 5. Remove local config: `rm -rf .aegis`.
192
+ 6. Remove cached GitHub App credentials if you used the app flow: `rm -f ~/.aegis/github-apps/YOUR-ORG-YOUR-REPO.env`.
193
+ 7. Optionally remove Aegis-only labels: `aegis:in-progress`, `aegis:needs-info`, `aegis:blocked`, `aegis:pr-opened`.
188
194
 
189
195
  ## How Pickup Works
190
196
 
@@ -87,8 +87,10 @@ function toSecrets(config) {
87
87
  VERCEL_TOKEN: config.vercelToken,
88
88
  VERCEL_PROJECT_ID: config.vercelProjectId,
89
89
  VERCEL_TEAM_ID: config.vercelTeamId,
90
+ AGENT_AUTH_METHOD: config.agentAuthMethod,
90
91
  AGENT_MODEL: config.agentModel,
91
92
  OPENAI_API_KEY: config.openaiApiKey,
93
+ CODEX_OAUTH_CREDENTIALS_B64: config.codexOauthCredentials,
92
94
  };
93
95
  }
94
96
  //# sourceMappingURL=deploy.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"deploy.js","sourceRoot":"","sources":["../../../src/cli/commands/deploy.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"deploy.js","sourceRoot":"","sources":["../../../src/cli/commands/deploy.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"disconnect.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/disconnect.ts"],"names":[],"mappings":"AAKA,eAAO,MAAM,iBAAiB,qDAQ5B,CAAC;AAEH,wBAAgB,kBAAkB,IAAI,IAAI,CA2DzC"}
1
+ {"version":3,"file":"disconnect.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/disconnect.ts"],"names":[],"mappings":"AAKA,eAAO,MAAM,iBAAiB,qDAQ5B,CAAC;AAEH,wBAAgB,kBAAkB,IAAI,IAAI,CAwEzC"}
@@ -21,7 +21,21 @@ export function runDisconnectGuide() {
21
21
  consola.log(" If you deployed Aegis, delete the Cloudflare Worker:");
22
22
  consola.log(` npx wrangler delete ${workerName}`);
23
23
  consola.log(" Also remove any Cloudflare secrets for Aegis if they remain.\n");
24
- consola.log("2. Remove GitHub access");
24
+ consola.log("2. Remove model access");
25
+ if (config.agentAuthMethod === "codex-account") {
26
+ consola.log(" You connected a Codex account.");
27
+ consola.log(" Open OpenAI/ChatGPT settings and revoke Codex/Aegis OAuth access.");
28
+ consola.log(" Also delete the CODEX_OAUTH_CREDENTIALS_B64 Cloudflare secret.");
29
+ }
30
+ else if (config.openaiApiKey) {
31
+ consola.log(" You used an OpenAI API key.");
32
+ consola.log(" Revoke the key in the OpenAI API dashboard if it was created only for Aegis.");
33
+ }
34
+ else {
35
+ consola.log(" No model credential is saved in local config.");
36
+ }
37
+ consola.log("");
38
+ consola.log("3. Remove GitHub access");
25
39
  if (config.githubAppId) {
26
40
  consola.log(" You used a GitHub App.");
27
41
  consola.log(` Open GitHub -> ${repo} -> Settings -> GitHub Apps, then uninstall the Aegis app.`);
@@ -36,7 +50,7 @@ export function runDisconnectGuide() {
36
50
  consola.log(" No GitHub token/app is saved in local config.");
37
51
  }
38
52
  consola.log("");
39
- consola.log("3. Remove webhooks");
53
+ consola.log("4. Remove webhooks");
40
54
  consola.log(` GitHub: open ${repo} -> Settings -> Webhooks, delete the Aegis webhook.`);
41
55
  if (config.linearApiKey) {
42
56
  consola.log(" Linear: open Linear Settings -> API/Webhooks, delete the Aegis webhook.");
@@ -46,7 +60,7 @@ export function runDisconnectGuide() {
46
60
  consola.log(' curl "https://api.telegram.org/bot$TELEGRAM_BOT_TOKEN/deleteWebhook"');
47
61
  }
48
62
  consola.log("");
49
- consola.log("4. Remove local config from this repo");
63
+ consola.log("5. Remove local config from this repo");
50
64
  consola.log(" rm -rf .aegis");
51
65
  if (config.monitoredRepo) {
52
66
  consola.log(" Remove this user's cached GitHub App credentials too:");
@@ -55,7 +69,7 @@ export function runDisconnectGuide() {
55
69
  consola.log(" If you installed Aegis as a dev dependency:");
56
70
  consola.log(" npm remove @nairon-ai/aegis");
57
71
  consola.log("");
58
- consola.log("5. Optional cleanup");
72
+ consola.log("6. Optional cleanup");
59
73
  consola.log(" Leave labels like bug and ready to implement if your team uses them.");
60
74
  consola.log(" Remove Aegis-only labels if you do not want them:");
61
75
  consola.log(" aegis:in-progress, aegis:needs-info, aegis:blocked, aegis:pr-opened");
@@ -1 +1 @@
1
- {"version":3,"file":"disconnect.js","sourceRoot":"","sources":["../../../src/cli/commands/disconnect.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"disconnect.js","sourceRoot":"","sources":["../../../src/cli/commands/disconnect.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"init.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/init.ts"],"names":[],"mappings":"AAkGA,eAAO,MAAM,WAAW,qDAKtB,CAAC;AAEH,wBAAgB,OAAO,IAAI,IAAI,CAc9B"}
1
+ {"version":3,"file":"init.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/init.ts"],"names":[],"mappings":"AAqGA,eAAO,MAAM,WAAW,qDAKtB,CAAC;AAEH,wBAAgB,OAAO,IAAI,IAAI,CAc9B"}
@@ -6,8 +6,11 @@ import { PROJECT_AEGIS_DIR } from "../paths.js";
6
6
  const ENV_EXAMPLE = `# Required
7
7
  MONITORED_REPO=KeyLead-Team/keylead
8
8
  BASE_BRANCH=main
9
- AGENT_MODEL=openai/gpt-5.5
10
- OPENAI_API_KEY=sk-...
9
+ AGENT_AUTH_METHOD=codex-account
10
+ AGENT_MODEL=openai-codex/gpt-5.5
11
+ CODEX_OAUTH_CREDENTIALS_B64=
12
+ # Or use AGENT_AUTH_METHOD=openai-api-key with OPENAI_API_KEY=sk-...
13
+ OPENAI_API_KEY=
11
14
 
12
15
  # Labels / automation
13
16
  READY_LABEL=ready to implement
@@ -1 +1 @@
1
- {"version":3,"file":"init.js","sourceRoot":"","sources":["../../../src/cli/commands/init.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAC/D,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,aAAa,EAAE,MAAM,OAAO,CAAC;AACtC,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAClC,OAAO,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAEhD,MAAM,WAAW,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA4CnB,CAAC;AAEF,MAAM,MAAM,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA4Cd,CAAC;AAEF,MAAM,CAAC,MAAM,WAAW,GAAG,aAAa,CAAC;IACxC,IAAI,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,WAAW,EAAE,qCAAqC,EAAE;IAC1E,KAAK,CAAC,GAAG;QACR,OAAO,EAAE,CAAC;IACX,CAAC;CACD,CAAC,CAAC;AAEH,MAAM,UAAU,OAAO;IACtB,SAAS,CAAC,iBAAiB,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAClD,cAAc,CAAC,OAAO,CAAC,iBAAiB,EAAE,YAAY,CAAC,EAAE,eAAe,CAAC,CAAC;IAC1E,cAAc,CAAC,OAAO,CAAC,iBAAiB,EAAE,cAAc,CAAC,EAAE,WAAW,CAAC,CAAC;IACxE,cAAc,CAAC,OAAO,CAAC,iBAAiB,EAAE,WAAW,CAAC,EAAE,MAAM,CAAC,CAAC;IAChE,OAAO,CAAC,OAAO,CAAC,iBAAiB,CAAC,CAAC;IACnC,OAAO,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;IACvB,OAAO,CAAC,GAAG,CAAC,8CAA8C,CAAC,CAAC;IAC5D,OAAO,CAAC,GAAG,CAAC,oDAAoD,CAAC,CAAC;IAClE,OAAO,CAAC,GAAG,CAAC,mCAAmC,CAAC,CAAC;IACjD,OAAO,CAAC,GAAG,CAAC,yDAAyD,CAAC,CAAC;IACvE,OAAO,CAAC,GAAG,CAAC,+CAA+C,CAAC,CAAC;IAC7D,OAAO,CAAC,GAAG,CAAC,uDAAuD,CAAC,CAAC;IACrE,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;AACjB,CAAC;AAED,SAAS,cAAc,CAAC,IAAY,EAAE,QAAgB;IACrD,IAAI,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC;QACtB,OAAO,CAAC,IAAI,CAAC,oBAAoB,IAAI,EAAE,CAAC,CAAC;QACzC,OAAO;IACR,CAAC;IACD,aAAa,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC;AAC/B,CAAC"}
1
+ {"version":3,"file":"init.js","sourceRoot":"","sources":["../../../src/cli/commands/init.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAC/D,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,aAAa,EAAE,MAAM,OAAO,CAAC;AACtC,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAClC,OAAO,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAEhD,MAAM,WAAW,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA+CnB,CAAC;AAEF,MAAM,MAAM,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA4Cd,CAAC;AAEF,MAAM,CAAC,MAAM,WAAW,GAAG,aAAa,CAAC;IACxC,IAAI,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,WAAW,EAAE,qCAAqC,EAAE;IAC1E,KAAK,CAAC,GAAG;QACR,OAAO,EAAE,CAAC;IACX,CAAC;CACD,CAAC,CAAC;AAEH,MAAM,UAAU,OAAO;IACtB,SAAS,CAAC,iBAAiB,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAClD,cAAc,CAAC,OAAO,CAAC,iBAAiB,EAAE,YAAY,CAAC,EAAE,eAAe,CAAC,CAAC;IAC1E,cAAc,CAAC,OAAO,CAAC,iBAAiB,EAAE,cAAc,CAAC,EAAE,WAAW,CAAC,CAAC;IACxE,cAAc,CAAC,OAAO,CAAC,iBAAiB,EAAE,WAAW,CAAC,EAAE,MAAM,CAAC,CAAC;IAChE,OAAO,CAAC,OAAO,CAAC,iBAAiB,CAAC,CAAC;IACnC,OAAO,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;IACvB,OAAO,CAAC,GAAG,CAAC,8CAA8C,CAAC,CAAC;IAC5D,OAAO,CAAC,GAAG,CAAC,oDAAoD,CAAC,CAAC;IAClE,OAAO,CAAC,GAAG,CAAC,mCAAmC,CAAC,CAAC;IACjD,OAAO,CAAC,GAAG,CAAC,yDAAyD,CAAC,CAAC;IACvE,OAAO,CAAC,GAAG,CAAC,+CAA+C,CAAC,CAAC;IAC7D,OAAO,CAAC,GAAG,CAAC,uDAAuD,CAAC,CAAC;IACrE,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;AACjB,CAAC;AAED,SAAS,cAAc,CAAC,IAAY,EAAE,QAAgB;IACrD,IAAI,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC;QACtB,OAAO,CAAC,IAAI,CAAC,oBAAoB,IAAI,EAAE,CAAC,CAAC;QACzC,OAAO;IACR,CAAC;IACD,aAAa,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC;AAC/B,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"setup.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/setup.ts"],"names":[],"mappings":"AAuCA,eAAO,MAAM,YAAY,qDAKvB,CAAC;AAEH,wBAAsB,cAAc,IAAI,OAAO,CAAC,IAAI,CAAC,CAoCpD"}
1
+ {"version":3,"file":"setup.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/setup.ts"],"names":[],"mappings":"AA6CA,eAAO,MAAM,YAAY,qDAKvB,CAAC;AAEH,wBAAsB,cAAc,IAAI,OAAO,CAAC,IAAI,CAAC,CAoCpD"}
@@ -3,7 +3,7 @@ import { existsSync, readFileSync, readdirSync, statSync } from "node:fs";
3
3
  import { resolve } from "node:path";
4
4
  import { defineCommand } from "citty";
5
5
  import { consola } from "consola";
6
- import { AGENT_MODEL_OPTIONS, DEFAULT_AGENT_MODEL } from "../../shared/constants.js";
6
+ import { CODEX_AGENT_MODEL_OPTIONS, DEFAULT_AGENT_AUTH_METHOD, DEFAULT_CODEX_AGENT_MODEL, DEFAULT_OPENAI_API_AGENT_MODEL, OPENAI_API_AGENT_MODEL_OPTIONS, } from "../../shared/constants.js";
7
7
  import { restoreGitHubAppCache, saveGitHubAppCache } from "../github-app-cache.js";
8
8
  import { runGitHubAppFlow } from "../github-app-flow.js";
9
9
  import { resolveEnvFileForWrite } from "../paths.js";
@@ -323,6 +323,47 @@ function sleep(ms) {
323
323
  function hasGitHubAppConfig(config) {
324
324
  return Boolean(config.githubAppId && config.githubAppPrivateKey && config.githubInstallationId);
325
325
  }
326
+ function hasLinearConfig(config) {
327
+ return Boolean(config.linearApiKey && config.linearTeamId);
328
+ }
329
+ function hasLinearWorkflowConfig(config) {
330
+ return Boolean(config.linearReadyStatus &&
331
+ config.linearInProgressStatus &&
332
+ config.linearNeedsInfoStatus &&
333
+ config.linearBlockedStatus &&
334
+ config.linearBugLabel);
335
+ }
336
+ function hasAutomationConfig(config) {
337
+ const authMethod = config.agentAuthMethod ?? DEFAULT_AGENT_AUTH_METHOD;
338
+ const hasModelKey = authMethod === "codex-account"
339
+ ? Boolean(config.codexOauthCredentials)
340
+ : !config.agentModel?.startsWith("openai/") || Boolean(config.openaiApiKey);
341
+ return Boolean(config.readyLabel &&
342
+ config.bugLabel &&
343
+ config.automationMode &&
344
+ config.agentAuthMethod &&
345
+ config.agentModel &&
346
+ hasModelKey);
347
+ }
348
+ function hasProductionContextConfig(config) {
349
+ return Boolean(config.contextProfile &&
350
+ (config.contextProfile === "minimal" ||
351
+ config.databaseUrl ||
352
+ (config.vercelToken && config.vercelProjectId)));
353
+ }
354
+ function hasTelegramConfig(config) {
355
+ return Boolean(config.telegramBotToken && config.telegramChatId);
356
+ }
357
+ function maskSecret(value) {
358
+ if (!value)
359
+ return "not configured";
360
+ if (value.length <= 8)
361
+ return "configured";
362
+ return `${value.slice(0, 4)}...${value.slice(-4)}`;
363
+ }
364
+ function encodeBase64Json(value) {
365
+ return Buffer.from(JSON.stringify(value), "utf-8").toString("base64");
366
+ }
326
367
  function detectInstalledAegisApps(monitoredRepo) {
327
368
  if (!monitoredRepo)
328
369
  return [];
@@ -371,6 +412,22 @@ function slugify(value) {
371
412
  .replace(/^-|-$/g, "");
372
413
  }
373
414
  async function setupLinear(config) {
415
+ let forceTeamSelection = false;
416
+ let forceWorkflowSelection = false;
417
+ if (hasLinearConfig(config)) {
418
+ printStep("Step 4: Linear already connected", [
419
+ `Using saved API key ${maskSecret(config.linearApiKey)}.`,
420
+ `Watching team ${config.linearTeamId}.`,
421
+ config.linearProjectId
422
+ ? `Limited to project ${config.linearProjectId}.`
423
+ : "Watching the whole Linear team.",
424
+ ]);
425
+ const reconfigure = await promptConfirm("Reconfigure Linear?", false);
426
+ if (!reconfigure)
427
+ return;
428
+ forceTeamSelection = true;
429
+ forceWorkflowSelection = true;
430
+ }
374
431
  printStep("Step 4: optional Linear connection", [
375
432
  "Use this only if your team tracks bugs in Linear.",
376
433
  "If you only use GitHub Issues, choose no.",
@@ -379,33 +436,52 @@ async function setupLinear(config) {
379
436
  const enable = await promptConfirm("Connect Linear too?", Boolean(config.linearApiKey));
380
437
  if (!enable)
381
438
  return;
382
- printStep("Linear API key", [
383
- "Open Linear settings, create a personal API key, then paste it here.",
384
- "Aegis uses it to read ready bug tickets and comment with status updates.",
385
- ]);
386
- config.linearApiKey = await promptText("Linear API key:", config.linearApiKey);
387
- await setupLinearTeam(config);
388
- printStep("Linear webhook secret", [
389
- "This protects Linear webhook calls after deploy.",
390
- "Choose yes and Aegis will generate one.",
391
- ]);
392
- const generateSecret = await promptConfirm("Generate a Linear webhook signing secret?", !config.linearWebhookSecret);
393
- config.linearWebhookSecret = generateSecret
394
- ? crypto.randomUUID()
395
- : await promptText("Linear webhook signing secret:", config.linearWebhookSecret);
396
- printStep("Linear statuses and labels", [
397
- "These names must match your Linear workflow.",
398
- "If your team uses the default names, press Enter through these prompts.",
399
- ]);
400
- config.linearReadyStatus = await promptText("Linear ready status name:", config.linearReadyStatus ?? "Ready to Implement");
401
- config.linearInProgressStatus = await promptText("Linear in-progress status name:", config.linearInProgressStatus ?? "In Progress");
402
- config.linearNeedsInfoStatus = await promptText("Linear needs-info status name:", config.linearNeedsInfoStatus ?? "Needs Info");
403
- config.linearBlockedStatus = await promptText("Linear blocked status name:", config.linearBlockedStatus ?? "Blocked");
404
- config.linearBugLabel = await promptText("Linear bug label:", config.linearBugLabel ?? "bug");
439
+ if (config.linearApiKey) {
440
+ consola.info(`Using saved Linear API key ${maskSecret(config.linearApiKey)}.`);
441
+ }
442
+ else {
443
+ printStep("Linear API key", [
444
+ "Open Linear settings, create a personal API key, then paste it here.",
445
+ "Aegis uses it to read ready bug tickets and comment with status updates.",
446
+ ]);
447
+ config.linearApiKey = await promptText("Linear API key:", config.linearApiKey);
448
+ }
449
+ await setupLinearTeam(config, forceTeamSelection);
450
+ if (config.linearWebhookSecret) {
451
+ consola.info("Linear webhook secret is already configured.");
452
+ }
453
+ else {
454
+ printStep("Linear webhook secret", [
455
+ "This protects Linear webhook calls after deploy.",
456
+ "Choose yes and Aegis will generate one.",
457
+ ]);
458
+ const generateSecret = await promptConfirm("Generate a Linear webhook signing secret?", true);
459
+ config.linearWebhookSecret = generateSecret
460
+ ? crypto.randomUUID()
461
+ : await promptText("Linear webhook signing secret:", config.linearWebhookSecret);
462
+ }
463
+ if (hasLinearWorkflowConfig(config) && !forceWorkflowSelection) {
464
+ consola.info("Linear statuses and bug label are already configured.");
465
+ }
466
+ else {
467
+ printStep("Linear statuses and labels", [
468
+ "These names must match your Linear workflow.",
469
+ "If your team uses the default names, press Enter through these prompts.",
470
+ ]);
471
+ config.linearReadyStatus = await promptText("Linear ready status name:", config.linearReadyStatus ?? "Ready to Implement");
472
+ config.linearInProgressStatus = await promptText("Linear in-progress status name:", config.linearInProgressStatus ?? "In Progress");
473
+ config.linearNeedsInfoStatus = await promptText("Linear needs-info status name:", config.linearNeedsInfoStatus ?? "Needs Info");
474
+ config.linearBlockedStatus = await promptText("Linear blocked status name:", config.linearBlockedStatus ?? "Blocked");
475
+ config.linearBugLabel = await promptText("Linear bug label:", config.linearBugLabel ?? "bug");
476
+ }
405
477
  }
406
- async function setupLinearTeam(config) {
478
+ async function setupLinearTeam(config, forceSelection = false) {
407
479
  if (!config.linearApiKey)
408
480
  return;
481
+ if (config.linearTeamId && !forceSelection) {
482
+ consola.info(`Using saved Linear team ${config.linearTeamId}.`);
483
+ return;
484
+ }
409
485
  printStep("Linear team/project", [
410
486
  "Aegis will fetch your Linear teams so you can pick one by name.",
411
487
  "Project ID is optional. Leave it blank to watch the whole team.",
@@ -464,6 +540,22 @@ function formatLinearTeam(team) {
464
540
  return `${team.name} (${team.key})`;
465
541
  }
466
542
  async function setupAutomation(config) {
543
+ if (hasAutomationConfig(config)) {
544
+ printStep("Steps 5-7: automation already configured", [
545
+ `GitHub labels: ${config.bugLabel}, ${config.readyLabel}.`,
546
+ `Mode: ${config.automationMode}.`,
547
+ `Auth: ${formatAgentAuthMethod(config.agentAuthMethod)}.`,
548
+ `Model: ${config.agentModel}.`,
549
+ config.agentAuthMethod === "codex-account"
550
+ ? "Codex account: connected."
551
+ : config.openaiApiKey
552
+ ? `OpenAI key: ${maskSecret(config.openaiApiKey)}.`
553
+ : "OpenAI key: not configured.",
554
+ ]);
555
+ const reconfigure = await promptConfirm("Reconfigure labels, mode, or model?", false);
556
+ if (!reconfigure)
557
+ return;
558
+ }
467
559
  printStep("Step 5: GitHub labels Aegis should watch", [
468
560
  "Aegis only picks up open issues with both labels.",
469
561
  "Default labels are bug and ready to implement.",
@@ -480,24 +572,93 @@ async function setupAutomation(config) {
480
572
  { label: "Plan first, ask approval before patching", value: "plan-first" },
481
573
  { label: "Auto-implement only bugs labeled low-risk", value: "auto-low-risk" },
482
574
  ], config.automationMode ?? "plan-first");
483
- printStep("Step 7: AI model", [
484
- "Use GPT-5.5 unless you know you want another OpenAI/Codex model.",
485
- "Flue model names look like provider/model-id, for example openai/gpt-5.5.",
575
+ await setupAgentAuth(config);
576
+ printStep("Step 7b: AI model", [
577
+ "Choose after auth, because Codex account models use openai-codex/... and API-key models use openai/...",
578
+ "Use GPT-5.5 unless you know you want a cheaper or faster model.",
486
579
  "Custom models need provider access and their provider key configured manually.",
487
580
  ]);
488
- config.agentModel = await promptAgentModel(config.agentModel);
581
+ config.agentModel = await promptAgentModel(config.agentModel, config.agentAuthMethod);
582
+ }
583
+ async function setupAgentAuth(config) {
584
+ printStep("Step 7: coding model account", [
585
+ "Choose Codex account if you want to use your ChatGPT/Codex subscription, like Sandcastle.",
586
+ "Choose OpenAI API key if you want normal platform API billing.",
587
+ "Aegis asks this before model selection because each auth method has a different model prefix.",
588
+ ]);
589
+ config.agentAuthMethod = await promptSelect("Model authentication:", [
590
+ { label: "Codex account / ChatGPT login (recommended)", value: "codex-account" },
591
+ { label: "OpenAI API key", value: "openai-api-key" },
592
+ ], config.agentAuthMethod ?? DEFAULT_AGENT_AUTH_METHOD);
593
+ if (config.agentAuthMethod === "codex-account") {
594
+ await setupCodexAccountAuth(config);
595
+ return;
596
+ }
597
+ await setupOpenAiApiKeyAuth(config);
598
+ }
599
+ async function setupCodexAccountAuth(config) {
600
+ config.openaiApiKey = undefined;
601
+ if (config.codexOauthCredentials) {
602
+ consola.info("Using saved Codex account credentials.");
603
+ if (!config.agentModel?.startsWith("openai-codex/")) {
604
+ config.agentModel = DEFAULT_CODEX_AGENT_MODEL;
605
+ }
606
+ return;
607
+ }
608
+ printStep("Connect Codex account", [
609
+ "A browser window will open for OpenAI/Codex login.",
610
+ "Aegis saves OAuth credentials to .aegis/.env and deploys them as a Cloudflare secret.",
611
+ "Only use this on a Worker you control. To disconnect later, run aegis disconnect and revoke Codex access in OpenAI settings.",
612
+ ]);
613
+ const { loginOpenAICodex } = await import("@mariozechner/pi-ai/oauth");
614
+ const credentials = await loginOpenAICodex({
615
+ onAuth: ({ url, instructions }) => {
616
+ consola.info(instructions ?? "Complete OpenAI login in your browser.");
617
+ consola.info(`Open: ${url}`);
618
+ openBrowser(url);
619
+ },
620
+ onPrompt: async (prompt) => await promptText(prompt.message, prompt.placeholder),
621
+ onProgress: (message) => consola.info(message),
622
+ onManualCodeInput: async () => await promptText("Paste OpenAI auth code or final redirect URL if the browser did not finish:", undefined),
623
+ originator: "aegis",
624
+ });
625
+ config.codexOauthCredentials = encodeBase64Json(credentials);
626
+ if (!config.agentModel?.startsWith("openai-codex/")) {
627
+ config.agentModel = DEFAULT_CODEX_AGENT_MODEL;
628
+ }
629
+ consola.success("Codex account connected.");
630
+ }
631
+ async function setupOpenAiApiKeyAuth(config) {
632
+ config.codexOauthCredentials = undefined;
633
+ if (!config.agentModel?.startsWith("openai/")) {
634
+ config.agentModel = DEFAULT_OPENAI_API_AGENT_MODEL;
635
+ }
489
636
  printStep("OpenAI API key", [
490
- "Paste your OpenAI API key if using an openai/... model.",
637
+ "Paste your OpenAI API key.",
491
638
  "It is stored in .aegis/.env and later copied to Cloudflare secrets during deploy.",
492
- "Leave blank only if you configured a different model provider yourself.",
639
+ "Use Codex account instead if you do not want to manage an API key.",
493
640
  ]);
494
- config.openaiApiKey = await promptText("OpenAI API key:", config.openaiApiKey);
641
+ if (config.openaiApiKey) {
642
+ consola.info(`Using saved OpenAI API key ${maskSecret(config.openaiApiKey)}.`);
643
+ }
644
+ else {
645
+ config.openaiApiKey = await promptText("OpenAI API key:", config.openaiApiKey);
646
+ }
495
647
  }
496
- async function promptAgentModel(current) {
497
- const selectedModel = current ?? DEFAULT_AGENT_MODEL;
498
- const knownValues = AGENT_MODEL_OPTIONS.map((option) => option.value);
648
+ function formatAgentAuthMethod(method) {
649
+ if (method === "codex-account")
650
+ return "Codex account";
651
+ if (method === "openai-api-key")
652
+ return "OpenAI API key";
653
+ return "not configured";
654
+ }
655
+ async function promptAgentModel(current, authMethod) {
656
+ const options = authMethod === "openai-api-key" ? OPENAI_API_AGENT_MODEL_OPTIONS : CODEX_AGENT_MODEL_OPTIONS;
657
+ const defaultModel = authMethod === "openai-api-key" ? DEFAULT_OPENAI_API_AGENT_MODEL : DEFAULT_CODEX_AGENT_MODEL;
658
+ const selectedModel = current ?? defaultModel;
659
+ const knownValues = options.map((option) => option.value);
499
660
  const customValue = "__custom__";
500
- const selected = await promptSelect("Flue model:", [...AGENT_MODEL_OPTIONS, { label: "Custom Flue provider/model string", value: customValue }], (knownValues.includes(selectedModel)
661
+ const selected = await promptSelect("Flue model:", [...options, { label: "Custom Flue provider/model string", value: customValue }], (knownValues.includes(selectedModel)
501
662
  ? selectedModel
502
663
  : customValue));
503
664
  if (selected !== customValue)
@@ -505,6 +666,23 @@ async function promptAgentModel(current) {
505
666
  return await promptText("Custom Flue model:", selectedModel);
506
667
  }
507
668
  async function setupProductionContext(config) {
669
+ if (hasProductionContextConfig(config)) {
670
+ printStep("Step 8: production context already configured", [
671
+ `Context profile: ${config.contextProfile}.`,
672
+ config.databaseUrl
673
+ ? "Read-only database URL: configured."
674
+ : "Read-only database URL: not set.",
675
+ config.vercelToken
676
+ ? `Vercel token: ${maskSecret(config.vercelToken)}.`
677
+ : "Vercel token: not set.",
678
+ config.vercelProjectId
679
+ ? `Vercel project: ${config.vercelProjectId}.`
680
+ : "Vercel project: not set.",
681
+ ]);
682
+ const reconfigure = await promptConfirm("Reconfigure production context?", false);
683
+ if (!reconfigure)
684
+ return;
685
+ }
508
686
  printStep("Step 8: production context", [
509
687
  "Start with Minimal. It uses only issue text and repo code.",
510
688
  "Production context lets Aegis inspect read-only database data and Vercel logs.",
@@ -527,6 +705,18 @@ async function setupProductionContext(config) {
527
705
  config.vercelTeamId = await promptText("Vercel team ID (optional):", config.vercelTeamId);
528
706
  }
529
707
  async function setupTelegram(config) {
708
+ if (hasTelegramConfig(config)) {
709
+ printStep("Step 9: Telegram already connected", [
710
+ `Bot token: ${maskSecret(config.telegramBotToken)}.`,
711
+ `Chat ID: ${config.telegramChatId}.`,
712
+ config.telegramWebhookSecret
713
+ ? "Telegram webhook secret: configured."
714
+ : "Telegram webhook secret: not configured.",
715
+ ]);
716
+ const reconfigure = await promptConfirm("Reconfigure Telegram?", false);
717
+ if (!reconfigure)
718
+ return;
719
+ }
530
720
  printStep("Step 9: optional Telegram approval pings", [
531
721
  "Use this if you want Aegis to message you when it needs approval.",
532
722
  "For the first local dry-run, choose no.",
@@ -539,18 +729,42 @@ async function setupTelegram(config) {
539
729
  "Create a bot with BotFather, paste the bot token, then paste your chat ID.",
540
730
  "Aegis will send short approval summaries to that chat.",
541
731
  ]);
542
- config.telegramBotToken = await promptText("Telegram bot token:", config.telegramBotToken);
543
- config.telegramChatId = await promptText("Telegram chat ID:", config.telegramChatId);
544
- printStep("Telegram webhook secret", [
545
- "This protects Telegram webhook calls after deploy.",
546
- "Choose yes and Aegis will generate one.",
547
- ]);
548
- const generateSecret = await promptConfirm("Generate a Telegram webhook secret?", !config.telegramWebhookSecret);
549
- config.telegramWebhookSecret = generateSecret
550
- ? crypto.randomUUID()
551
- : await promptText("Telegram webhook secret:", config.telegramWebhookSecret);
732
+ if (config.telegramBotToken) {
733
+ consola.info(`Using saved Telegram bot token ${maskSecret(config.telegramBotToken)}.`);
734
+ }
735
+ else {
736
+ config.telegramBotToken = await promptText("Telegram bot token:", config.telegramBotToken);
737
+ }
738
+ if (config.telegramChatId) {
739
+ consola.info(`Using saved Telegram chat ID ${config.telegramChatId}.`);
740
+ }
741
+ else {
742
+ config.telegramChatId = await promptText("Telegram chat ID:", config.telegramChatId);
743
+ }
744
+ if (config.telegramWebhookSecret) {
745
+ consola.info("Telegram webhook secret is already configured.");
746
+ }
747
+ else {
748
+ printStep("Telegram webhook secret", [
749
+ "This protects Telegram webhook calls after deploy.",
750
+ "Choose yes and Aegis will generate one.",
751
+ ]);
752
+ const generateSecret = await promptConfirm("Generate a Telegram webhook secret?", true);
753
+ config.telegramWebhookSecret = generateSecret
754
+ ? crypto.randomUUID()
755
+ : await promptText("Telegram webhook secret:", config.telegramWebhookSecret);
756
+ }
552
757
  }
553
758
  async function setupWorker(config) {
759
+ if (config.workerUrl) {
760
+ printStep("Step 10: Worker URL already saved", [
761
+ `Using ${config.workerUrl}.`,
762
+ "Deploy updates this automatically when possible.",
763
+ ]);
764
+ const reconfigure = await promptConfirm("Reconfigure Worker URL?", false);
765
+ if (!reconfigure)
766
+ return;
767
+ }
554
768
  printStep("Step 10: Worker URL", [
555
769
  "Leave this blank before your first deploy.",
556
770
  "After deploy, Aegis saves the Worker URL automatically.",