longer-agent 0.1.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.
- package/LICENSE +21 -0
- package/README.md +227 -0
- package/README.zh-CN.md +227 -0
- package/agent_templates/executor/agent.yaml +22 -0
- package/agent_templates/executor/system_prompt.md +17 -0
- package/agent_templates/explorer/agent.yaml +13 -0
- package/agent_templates/explorer/system_prompt.md +19 -0
- package/agent_templates/main/agent.yaml +7 -0
- package/agent_templates/main/system_prompt.md +45 -0
- package/configExample.yaml +83 -0
- package/dist/agents/agent.d.ts +79 -0
- package/dist/agents/agent.d.ts.map +1 -0
- package/dist/agents/agent.js +156 -0
- package/dist/agents/agent.js.map +1 -0
- package/dist/agents/tool-loop.d.ts +140 -0
- package/dist/agents/tool-loop.d.ts.map +1 -0
- package/dist/agents/tool-loop.js +465 -0
- package/dist/agents/tool-loop.js.map +1 -0
- package/dist/ask.d.ts +81 -0
- package/dist/ask.d.ts.map +1 -0
- package/dist/ask.js +34 -0
- package/dist/ask.js.map +1 -0
- package/dist/auth/openai-oauth.d.ts +66 -0
- package/dist/auth/openai-oauth.d.ts.map +1 -0
- package/dist/auth/openai-oauth.js +640 -0
- package/dist/auth/openai-oauth.js.map +1 -0
- package/dist/cli.d.ts +14 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +254 -0
- package/dist/cli.js.map +1 -0
- package/dist/commands.d.ts +118 -0
- package/dist/commands.d.ts.map +1 -0
- package/dist/commands.js +862 -0
- package/dist/commands.js.map +1 -0
- package/dist/config.d.ts +130 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +648 -0
- package/dist/config.js.map +1 -0
- package/dist/context-rendering.d.ts +69 -0
- package/dist/context-rendering.d.ts.map +1 -0
- package/dist/context-rendering.js +250 -0
- package/dist/context-rendering.js.map +1 -0
- package/dist/document-projection.d.ts +12 -0
- package/dist/document-projection.d.ts.map +1 -0
- package/dist/document-projection.js +75 -0
- package/dist/document-projection.js.map +1 -0
- package/dist/ephemeral-log.d.ts +15 -0
- package/dist/ephemeral-log.d.ts.map +1 -0
- package/dist/ephemeral-log.js +173 -0
- package/dist/ephemeral-log.js.map +1 -0
- package/dist/file-attach.d.ts +89 -0
- package/dist/file-attach.d.ts.map +1 -0
- package/dist/file-attach.js +571 -0
- package/dist/file-attach.js.map +1 -0
- package/dist/index.d.ts +29 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +43 -0
- package/dist/index.js.map +1 -0
- package/dist/init-wizard.d.ts +13 -0
- package/dist/init-wizard.d.ts.map +1 -0
- package/dist/init-wizard.js +328 -0
- package/dist/init-wizard.js.map +1 -0
- package/dist/log-entry.d.ts +104 -0
- package/dist/log-entry.d.ts.map +1 -0
- package/dist/log-entry.js +292 -0
- package/dist/log-entry.js.map +1 -0
- package/dist/log-projection.d.ts +73 -0
- package/dist/log-projection.d.ts.map +1 -0
- package/dist/log-projection.js +651 -0
- package/dist/log-projection.js.map +1 -0
- package/dist/mcp-client.d.ts +55 -0
- package/dist/mcp-client.d.ts.map +1 -0
- package/dist/mcp-client.js +402 -0
- package/dist/mcp-client.js.map +1 -0
- package/dist/model-selection.d.ts +16 -0
- package/dist/model-selection.d.ts.map +1 -0
- package/dist/model-selection.js +181 -0
- package/dist/model-selection.js.map +1 -0
- package/dist/network-retry.d.ts +38 -0
- package/dist/network-retry.d.ts.map +1 -0
- package/dist/network-retry.js +140 -0
- package/dist/network-retry.js.map +1 -0
- package/dist/persistence.d.ts +104 -0
- package/dist/persistence.d.ts.map +1 -0
- package/dist/persistence.js +644 -0
- package/dist/persistence.js.map +1 -0
- package/dist/primitives/context.d.ts +29 -0
- package/dist/primitives/context.d.ts.map +1 -0
- package/dist/primitives/context.js +85 -0
- package/dist/primitives/context.js.map +1 -0
- package/dist/progress.d.ts +51 -0
- package/dist/progress.d.ts.map +1 -0
- package/dist/progress.js +229 -0
- package/dist/progress.js.map +1 -0
- package/dist/provider-presets.d.ts +34 -0
- package/dist/provider-presets.d.ts.map +1 -0
- package/dist/provider-presets.js +181 -0
- package/dist/provider-presets.js.map +1 -0
- package/dist/providers/anthropic.d.ts +32 -0
- package/dist/providers/anthropic.d.ts.map +1 -0
- package/dist/providers/anthropic.js +450 -0
- package/dist/providers/anthropic.js.map +1 -0
- package/dist/providers/base.d.ts +135 -0
- package/dist/providers/base.d.ts.map +1 -0
- package/dist/providers/base.js +104 -0
- package/dist/providers/base.js.map +1 -0
- package/dist/providers/glm.d.ts +18 -0
- package/dist/providers/glm.d.ts.map +1 -0
- package/dist/providers/glm.js +59 -0
- package/dist/providers/glm.js.map +1 -0
- package/dist/providers/kimi.d.ts +23 -0
- package/dist/providers/kimi.d.ts.map +1 -0
- package/dist/providers/kimi.js +89 -0
- package/dist/providers/kimi.js.map +1 -0
- package/dist/providers/minimax.d.ts +20 -0
- package/dist/providers/minimax.d.ts.map +1 -0
- package/dist/providers/minimax.js +192 -0
- package/dist/providers/minimax.js.map +1 -0
- package/dist/providers/openai-chat.d.ts +33 -0
- package/dist/providers/openai-chat.d.ts.map +1 -0
- package/dist/providers/openai-chat.js +543 -0
- package/dist/providers/openai-chat.js.map +1 -0
- package/dist/providers/openai-responses.d.ts +26 -0
- package/dist/providers/openai-responses.d.ts.map +1 -0
- package/dist/providers/openai-responses.js +443 -0
- package/dist/providers/openai-responses.js.map +1 -0
- package/dist/providers/openrouter.d.ts +24 -0
- package/dist/providers/openrouter.d.ts.map +1 -0
- package/dist/providers/openrouter.js +177 -0
- package/dist/providers/openrouter.js.map +1 -0
- package/dist/providers/registry.d.ts +7 -0
- package/dist/providers/registry.d.ts.map +1 -0
- package/dist/providers/registry.js +38 -0
- package/dist/providers/registry.js.map +1 -0
- package/dist/security/path.d.ts +51 -0
- package/dist/security/path.d.ts.map +1 -0
- package/dist/security/path.js +187 -0
- package/dist/security/path.js.map +1 -0
- package/dist/security/sensitive-files.d.ts +3 -0
- package/dist/security/sensitive-files.d.ts.map +1 -0
- package/dist/security/sensitive-files.js +41 -0
- package/dist/security/sensitive-files.js.map +1 -0
- package/dist/session.d.ts +446 -0
- package/dist/session.d.ts.map +1 -0
- package/dist/session.js +4595 -0
- package/dist/session.js.map +1 -0
- package/dist/settings.d.ts +46 -0
- package/dist/settings.d.ts.map +1 -0
- package/dist/settings.js +134 -0
- package/dist/settings.js.map +1 -0
- package/dist/show-context.d.ts +35 -0
- package/dist/show-context.d.ts.map +1 -0
- package/dist/show-context.js +320 -0
- package/dist/show-context.js.map +1 -0
- package/dist/skills/loader.d.ts +49 -0
- package/dist/skills/loader.d.ts.map +1 -0
- package/dist/skills/loader.js +166 -0
- package/dist/skills/loader.js.map +1 -0
- package/dist/summarize-context.d.ts +29 -0
- package/dist/summarize-context.d.ts.map +1 -0
- package/dist/summarize-context.js +247 -0
- package/dist/summarize-context.js.map +1 -0
- package/dist/templates/loader.d.ts +104 -0
- package/dist/templates/loader.d.ts.map +1 -0
- package/dist/templates/loader.js +514 -0
- package/dist/templates/loader.js.map +1 -0
- package/dist/tools/basic.d.ts +29 -0
- package/dist/tools/basic.d.ts.map +1 -0
- package/dist/tools/basic.js +2079 -0
- package/dist/tools/basic.js.map +1 -0
- package/dist/tools/comm.d.ts +17 -0
- package/dist/tools/comm.d.ts.map +1 -0
- package/dist/tools/comm.js +192 -0
- package/dist/tools/comm.js.map +1 -0
- package/dist/tools/web-fetch.d.ts +11 -0
- package/dist/tools/web-fetch.d.ts.map +1 -0
- package/dist/tools/web-fetch.js +237 -0
- package/dist/tools/web-fetch.js.map +1 -0
- package/dist/tools/web-search.d.ts +24 -0
- package/dist/tools/web-search.d.ts.map +1 -0
- package/dist/tools/web-search.js +51 -0
- package/dist/tools/web-search.js.map +1 -0
- package/dist/tui/app.d.ts +35 -0
- package/dist/tui/app.d.ts.map +1 -0
- package/dist/tui/app.js +1042 -0
- package/dist/tui/app.js.map +1 -0
- package/dist/tui/checkbox-picker.d.ts +35 -0
- package/dist/tui/checkbox-picker.d.ts.map +1 -0
- package/dist/tui/checkbox-picker.js +85 -0
- package/dist/tui/checkbox-picker.js.map +1 -0
- package/dist/tui/command-picker.d.ts +31 -0
- package/dist/tui/command-picker.d.ts.map +1 -0
- package/dist/tui/command-picker.js +113 -0
- package/dist/tui/command-picker.js.map +1 -0
- package/dist/tui/components/ask-panel.d.ts +21 -0
- package/dist/tui/components/ask-panel.d.ts.map +1 -0
- package/dist/tui/components/ask-panel.js +81 -0
- package/dist/tui/components/ask-panel.js.map +1 -0
- package/dist/tui/components/conversation-panel.d.ts +68 -0
- package/dist/tui/components/conversation-panel.d.ts.map +1 -0
- package/dist/tui/components/conversation-panel.js +611 -0
- package/dist/tui/components/conversation-panel.js.map +1 -0
- package/dist/tui/components/input-panel.d.ts +27 -0
- package/dist/tui/components/input-panel.d.ts.map +1 -0
- package/dist/tui/components/input-panel.js +725 -0
- package/dist/tui/components/input-panel.js.map +1 -0
- package/dist/tui/components/logo-panel.d.ts +14 -0
- package/dist/tui/components/logo-panel.d.ts.map +1 -0
- package/dist/tui/components/logo-panel.js +37 -0
- package/dist/tui/components/logo-panel.js.map +1 -0
- package/dist/tui/components/plan-panel.d.ts +10 -0
- package/dist/tui/components/plan-panel.d.ts.map +1 -0
- package/dist/tui/components/plan-panel.js +8 -0
- package/dist/tui/components/plan-panel.js.map +1 -0
- package/dist/tui/components/status-bar.d.ts +24 -0
- package/dist/tui/components/status-bar.d.ts.map +1 -0
- package/dist/tui/components/status-bar.js +80 -0
- package/dist/tui/components/status-bar.js.map +1 -0
- package/dist/tui/input/editor-state.d.ts +22 -0
- package/dist/tui/input/editor-state.d.ts.map +1 -0
- package/dist/tui/input/editor-state.js +157 -0
- package/dist/tui/input/editor-state.js.map +1 -0
- package/dist/tui/input/keymap.d.ts +3 -0
- package/dist/tui/input/keymap.d.ts.map +1 -0
- package/dist/tui/input/keymap.js +72 -0
- package/dist/tui/input/keymap.js.map +1 -0
- package/dist/tui/input/paste-slots.d.ts +17 -0
- package/dist/tui/input/paste-slots.d.ts.map +1 -0
- package/dist/tui/input/paste-slots.js +46 -0
- package/dist/tui/input/paste-slots.js.map +1 -0
- package/dist/tui/input/paste.d.ts +15 -0
- package/dist/tui/input/paste.d.ts.map +1 -0
- package/dist/tui/input/paste.js +35 -0
- package/dist/tui/input/paste.js.map +1 -0
- package/dist/tui/input/protocol.d.ts +9 -0
- package/dist/tui/input/protocol.d.ts.map +1 -0
- package/dist/tui/input/protocol.js +387 -0
- package/dist/tui/input/protocol.js.map +1 -0
- package/dist/tui/input/sanitize.d.ts +6 -0
- package/dist/tui/input/sanitize.d.ts.map +1 -0
- package/dist/tui/input/sanitize.js +20 -0
- package/dist/tui/input/sanitize.js.map +1 -0
- package/dist/tui/input/types.d.ts +18 -0
- package/dist/tui/input/types.d.ts.map +1 -0
- package/dist/tui/input/types.js +2 -0
- package/dist/tui/input/types.js.map +1 -0
- package/dist/tui/launch.d.ts +23 -0
- package/dist/tui/launch.d.ts.map +1 -0
- package/dist/tui/launch.js +104 -0
- package/dist/tui/launch.js.map +1 -0
- package/dist/tui/theme.d.ts +20 -0
- package/dist/tui/theme.d.ts.map +1 -0
- package/dist/tui/theme.js +29 -0
- package/dist/tui/theme.js.map +1 -0
- package/dist/tui/types.d.ts +136 -0
- package/dist/tui/types.d.ts.map +1 -0
- package/dist/tui/types.js +9 -0
- package/dist/tui/types.js.map +1 -0
- package/package.json +76 -0
- package/prompts/sections/agents_md.md +23 -0
- package/prompts/sections/important_log.md +16 -0
- package/prompts/sections/system_mechanisms.md +18 -0
- package/prompts/tools/apply_patch.md +31 -0
- package/prompts/tools/ask.md +18 -0
- package/prompts/tools/bash.md +13 -0
- package/prompts/tools/bash_background.md +9 -0
- package/prompts/tools/bash_output.md +9 -0
- package/prompts/tools/check_status.md +3 -0
- package/prompts/tools/diff.md +5 -0
- package/prompts/tools/edit_file.md +11 -0
- package/prompts/tools/glob.md +7 -0
- package/prompts/tools/grep.md +20 -0
- package/prompts/tools/kill_agent.md +3 -0
- package/prompts/tools/kill_shell.md +5 -0
- package/prompts/tools/list_dir.md +5 -0
- package/prompts/tools/plan.md +252 -0
- package/prompts/tools/read_file.md +9 -0
- package/prompts/tools/show_context.md +12 -0
- package/prompts/tools/skill.md +7 -0
- package/prompts/tools/spawn_agent.md +195 -0
- package/prompts/tools/summarize_context.md +122 -0
- package/prompts/tools/test.md +5 -0
- package/prompts/tools/wait.md +17 -0
- package/prompts/tools/web_fetch.md +9 -0
- package/prompts/tools/web_search.md +5 -0
- package/prompts/tools/write_file.md +11 -0
- package/skills/.staging/.gitkeep +0 -0
- package/skills/explain-code/SKILL.md +15 -0
- package/skills/skill-manager/SKILL.md +83 -0
|
@@ -0,0 +1,640 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* OpenAI OAuth for ChatGPT account login.
|
|
3
|
+
*
|
|
4
|
+
* Two login methods:
|
|
5
|
+
* 1. Browser login (PKCE) — recommended, opens browser for one-click auth
|
|
6
|
+
* 2. Device code — fallback for SSH / headless environments
|
|
7
|
+
*
|
|
8
|
+
* Token persistence in ~/.longeragent/auth.json with automatic refresh.
|
|
9
|
+
* No external dependencies — uses Node 18+ built-in fetch, crypto, http.
|
|
10
|
+
*/
|
|
11
|
+
import { createHash, randomBytes } from "node:crypto";
|
|
12
|
+
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
|
|
13
|
+
import { createServer } from "node:http";
|
|
14
|
+
import { homedir, platform } from "node:os";
|
|
15
|
+
import { join } from "node:path";
|
|
16
|
+
import { execSync } from "node:child_process";
|
|
17
|
+
import { confirm, select } from "@inquirer/prompts";
|
|
18
|
+
import { LONGERAGENT_HOME_DIR } from "../config.js";
|
|
19
|
+
// =============================================================================
|
|
20
|
+
// Constants
|
|
21
|
+
// =============================================================================
|
|
22
|
+
const ISSUER = "https://auth.openai.com";
|
|
23
|
+
const CLIENT_ID = "app_EMoamEEZ73f0CkXaXp7hrann";
|
|
24
|
+
const TOKEN_URL = `${ISSUER}/oauth/token`;
|
|
25
|
+
const AUTHORIZE_URL = `${ISSUER}/oauth/authorize`;
|
|
26
|
+
const DEVICE_CODE_URL = `${ISSUER}/api/accounts/deviceauth/usercode`;
|
|
27
|
+
const DEVICE_POLL_URL = `${ISSUER}/api/accounts/deviceauth/token`;
|
|
28
|
+
const DEVICE_VERIFY_URL = `${ISSUER}/codex/device`;
|
|
29
|
+
const DEVICE_REDIRECT_URI = `${ISSUER}/deviceauth/callback`;
|
|
30
|
+
export const CODEX_BASE_URL = "https://chatgpt.com/backend-api/codex";
|
|
31
|
+
// PKCE browser flow
|
|
32
|
+
const PKCE_CALLBACK_PORT = 1455;
|
|
33
|
+
const PKCE_CALLBACK_HOST = "127.0.0.1";
|
|
34
|
+
const PKCE_REDIRECT_URI = `http://localhost:${PKCE_CALLBACK_PORT}/auth/callback`;
|
|
35
|
+
const PKCE_SCOPES = "openid profile email offline_access";
|
|
36
|
+
/** Refresh the access token 2 minutes before it actually expires. */
|
|
37
|
+
const REFRESH_SKEW_SECONDS = 120;
|
|
38
|
+
/** Maximum time to wait for the user to complete login. */
|
|
39
|
+
const AUTH_TIMEOUT_MS = 15 * 60 * 1000; // 15 minutes
|
|
40
|
+
/** Timeout for individual HTTP requests. */
|
|
41
|
+
const HTTP_TIMEOUT_MS = 15_000;
|
|
42
|
+
// =============================================================================
|
|
43
|
+
// Auth store (sync file I/O)
|
|
44
|
+
// =============================================================================
|
|
45
|
+
function authStorePath() {
|
|
46
|
+
return join(homedir(), LONGERAGENT_HOME_DIR, "auth.json");
|
|
47
|
+
}
|
|
48
|
+
export function loadAuthStore() {
|
|
49
|
+
const p = authStorePath();
|
|
50
|
+
if (!existsSync(p))
|
|
51
|
+
return { version: 1 };
|
|
52
|
+
try {
|
|
53
|
+
const raw = readFileSync(p, "utf-8");
|
|
54
|
+
const data = JSON.parse(raw);
|
|
55
|
+
if (data && typeof data === "object" && data.version === 1) {
|
|
56
|
+
return data;
|
|
57
|
+
}
|
|
58
|
+
return { version: 1 };
|
|
59
|
+
}
|
|
60
|
+
catch {
|
|
61
|
+
return { version: 1 };
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
function saveAuthStore(store) {
|
|
65
|
+
const p = authStorePath();
|
|
66
|
+
const dir = join(homedir(), LONGERAGENT_HOME_DIR);
|
|
67
|
+
mkdirSync(dir, { recursive: true });
|
|
68
|
+
writeFileSync(p, JSON.stringify(store, null, 2) + "\n", {
|
|
69
|
+
encoding: "utf-8",
|
|
70
|
+
mode: 0o600,
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
export function saveOAuthTokens(tokens) {
|
|
74
|
+
const store = loadAuthStore();
|
|
75
|
+
store.openai_codex = {
|
|
76
|
+
access_token: tokens.access_token,
|
|
77
|
+
refresh_token: tokens.refresh_token,
|
|
78
|
+
last_refresh: new Date().toISOString().replace(/\.\d{3}Z$/, "Z"),
|
|
79
|
+
};
|
|
80
|
+
saveAuthStore(store);
|
|
81
|
+
}
|
|
82
|
+
export function clearOAuthTokens() {
|
|
83
|
+
const store = loadAuthStore();
|
|
84
|
+
delete store.openai_codex;
|
|
85
|
+
saveAuthStore(store);
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* Read the stored OAuth access token (sync).
|
|
89
|
+
* Returns null if no tokens are stored.
|
|
90
|
+
*/
|
|
91
|
+
export function readOAuthAccessToken() {
|
|
92
|
+
const store = loadAuthStore();
|
|
93
|
+
const token = store.openai_codex?.access_token;
|
|
94
|
+
return typeof token === "string" && token.trim() !== "" ? token : null;
|
|
95
|
+
}
|
|
96
|
+
/** Check whether OAuth tokens exist in the auth store. */
|
|
97
|
+
export function hasOAuthTokens() {
|
|
98
|
+
const store = loadAuthStore();
|
|
99
|
+
const codex = store.openai_codex;
|
|
100
|
+
return Boolean(codex &&
|
|
101
|
+
typeof codex.access_token === "string" && codex.access_token.trim() !== "" &&
|
|
102
|
+
typeof codex.refresh_token === "string" && codex.refresh_token.trim() !== "");
|
|
103
|
+
}
|
|
104
|
+
// =============================================================================
|
|
105
|
+
// JWT helpers
|
|
106
|
+
// =============================================================================
|
|
107
|
+
function decodeJwtPayload(token) {
|
|
108
|
+
const parts = token.split(".");
|
|
109
|
+
if (parts.length < 2)
|
|
110
|
+
return {};
|
|
111
|
+
let payload = parts[1];
|
|
112
|
+
payload += "=".repeat((4 - (payload.length % 4)) % 4);
|
|
113
|
+
try {
|
|
114
|
+
const raw = Buffer.from(payload, "base64url").toString("utf-8");
|
|
115
|
+
const claims = JSON.parse(raw);
|
|
116
|
+
return typeof claims === "object" && claims !== null ? claims : {};
|
|
117
|
+
}
|
|
118
|
+
catch {
|
|
119
|
+
return {};
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
/**
|
|
123
|
+
* Check whether an OAuth access token is about to expire.
|
|
124
|
+
* Returns true if the token will expire within `skewSeconds` seconds,
|
|
125
|
+
* or if the expiry cannot be determined.
|
|
126
|
+
*/
|
|
127
|
+
export function isTokenExpiring(accessToken, skewSeconds = REFRESH_SKEW_SECONDS) {
|
|
128
|
+
const claims = decodeJwtPayload(accessToken);
|
|
129
|
+
const exp = claims["exp"];
|
|
130
|
+
if (typeof exp !== "number")
|
|
131
|
+
return false;
|
|
132
|
+
return exp <= Math.floor(Date.now() / 1000) + Math.max(0, skewSeconds);
|
|
133
|
+
}
|
|
134
|
+
function getTokenExpiry(accessToken) {
|
|
135
|
+
const claims = decodeJwtPayload(accessToken);
|
|
136
|
+
const exp = claims["exp"];
|
|
137
|
+
if (typeof exp !== "number")
|
|
138
|
+
return null;
|
|
139
|
+
return new Date(exp * 1000);
|
|
140
|
+
}
|
|
141
|
+
// =============================================================================
|
|
142
|
+
// HTTP helpers
|
|
143
|
+
// =============================================================================
|
|
144
|
+
async function fetchJson(url, init) {
|
|
145
|
+
const controller = new AbortController();
|
|
146
|
+
const timeout = setTimeout(() => controller.abort(), HTTP_TIMEOUT_MS);
|
|
147
|
+
try {
|
|
148
|
+
const resp = await fetch(url, { ...init, signal: controller.signal });
|
|
149
|
+
const data = (await resp.json());
|
|
150
|
+
return { status: resp.status, data };
|
|
151
|
+
}
|
|
152
|
+
finally {
|
|
153
|
+
clearTimeout(timeout);
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
async function fetchForm(url, body) {
|
|
157
|
+
return fetchJson(url, {
|
|
158
|
+
method: "POST",
|
|
159
|
+
headers: { "Content-Type": "application/x-www-form-urlencoded" },
|
|
160
|
+
body: new URLSearchParams(body).toString(),
|
|
161
|
+
});
|
|
162
|
+
}
|
|
163
|
+
// =============================================================================
|
|
164
|
+
// Platform helpers
|
|
165
|
+
// =============================================================================
|
|
166
|
+
function openBrowser(url) {
|
|
167
|
+
try {
|
|
168
|
+
const p = platform();
|
|
169
|
+
if (p === "darwin") {
|
|
170
|
+
execSync(`open ${JSON.stringify(url)}`, { stdio: "ignore" });
|
|
171
|
+
}
|
|
172
|
+
else if (p === "win32") {
|
|
173
|
+
execSync(`start "" ${JSON.stringify(url)}`, { stdio: "ignore" });
|
|
174
|
+
}
|
|
175
|
+
else {
|
|
176
|
+
execSync(`xdg-open ${JSON.stringify(url)}`, { stdio: "ignore" });
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
catch {
|
|
180
|
+
// Browser open failed — user will need to copy the URL manually
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
function isRemoteSession() {
|
|
184
|
+
return Boolean(process.env["SSH_CLIENT"] || process.env["SSH_TTY"]);
|
|
185
|
+
}
|
|
186
|
+
// =============================================================================
|
|
187
|
+
// PKCE helpers
|
|
188
|
+
// =============================================================================
|
|
189
|
+
function generateCodeVerifier() {
|
|
190
|
+
// 32 random bytes → 43 base64url chars (RFC 7636 recommends 43-128)
|
|
191
|
+
return randomBytes(32).toString("base64url");
|
|
192
|
+
}
|
|
193
|
+
function generateCodeChallenge(verifier) {
|
|
194
|
+
return createHash("sha256").update(verifier).digest("base64url");
|
|
195
|
+
}
|
|
196
|
+
function generateState() {
|
|
197
|
+
return randomBytes(16).toString("hex");
|
|
198
|
+
}
|
|
199
|
+
// =============================================================================
|
|
200
|
+
// PKCE Browser OAuth flow
|
|
201
|
+
// =============================================================================
|
|
202
|
+
/**
|
|
203
|
+
* Start a temporary HTTP server on localhost to capture the OAuth callback.
|
|
204
|
+
* Returns a promise that resolves with the authorization code.
|
|
205
|
+
*/
|
|
206
|
+
function waitForCallback(expectedState) {
|
|
207
|
+
let resolvePromise;
|
|
208
|
+
let rejectPromise;
|
|
209
|
+
const promise = new Promise((resolve, reject) => {
|
|
210
|
+
resolvePromise = resolve;
|
|
211
|
+
rejectPromise = reject;
|
|
212
|
+
});
|
|
213
|
+
const server = createServer({ keepAliveTimeout: 1 }, (req, res) => {
|
|
214
|
+
res.setHeader("Connection", "close");
|
|
215
|
+
const url = new URL(req.url ?? "/", `http://${PKCE_CALLBACK_HOST}:${PKCE_CALLBACK_PORT}`);
|
|
216
|
+
if (url.pathname !== "/auth/callback") {
|
|
217
|
+
res.writeHead(404, { "Content-Type": "text/plain" });
|
|
218
|
+
res.end("Not found");
|
|
219
|
+
return;
|
|
220
|
+
}
|
|
221
|
+
const code = url.searchParams.get("code");
|
|
222
|
+
const state = url.searchParams.get("state");
|
|
223
|
+
const error = url.searchParams.get("error");
|
|
224
|
+
if (error) {
|
|
225
|
+
const desc = url.searchParams.get("error_description") || error;
|
|
226
|
+
res.writeHead(200, { "Content-Type": "text/html" });
|
|
227
|
+
res.end(callbackHtml("Login Failed", `Error: ${desc}. You can close this tab.`));
|
|
228
|
+
rejectPromise(new Error(`OAuth error: ${desc}`));
|
|
229
|
+
return;
|
|
230
|
+
}
|
|
231
|
+
if (!code || state !== expectedState) {
|
|
232
|
+
res.writeHead(400, { "Content-Type": "text/html" });
|
|
233
|
+
res.end(callbackHtml("Login Failed", "Invalid callback. Please try again."));
|
|
234
|
+
rejectPromise(new Error("Invalid OAuth callback: missing code or state mismatch."));
|
|
235
|
+
return;
|
|
236
|
+
}
|
|
237
|
+
res.writeHead(200, { "Content-Type": "text/html" });
|
|
238
|
+
res.end(callbackHtml("Login Successful", "You can close this tab and return to the terminal."));
|
|
239
|
+
resolvePromise(code);
|
|
240
|
+
});
|
|
241
|
+
server.listen(PKCE_CALLBACK_PORT, PKCE_CALLBACK_HOST);
|
|
242
|
+
return { promise, server };
|
|
243
|
+
}
|
|
244
|
+
function callbackHtml(title, message) {
|
|
245
|
+
return `<!DOCTYPE html><html><head><title>${title}</title>
|
|
246
|
+
<style>body{font-family:system-ui,sans-serif;display:flex;justify-content:center;
|
|
247
|
+
align-items:center;height:100vh;margin:0;background:#f9fafb}
|
|
248
|
+
.card{text-align:center;padding:2rem;border-radius:12px;background:#fff;
|
|
249
|
+
box-shadow:0 2px 8px rgba(0,0,0,.1)}h1{margin:0 0 .5rem;font-size:1.5rem}
|
|
250
|
+
p{color:#666;margin:0}</style></head>
|
|
251
|
+
<body><div class="card"><h1>${title}</h1><p>${message}</p></div></body></html>`;
|
|
252
|
+
}
|
|
253
|
+
/**
|
|
254
|
+
* Execute the PKCE browser OAuth flow.
|
|
255
|
+
*
|
|
256
|
+
* 1. Generate PKCE verifier + challenge + state
|
|
257
|
+
* 2. Start local callback server on port 1455
|
|
258
|
+
* 3. Open browser to OpenAI authorization URL
|
|
259
|
+
* 4. Wait for callback with authorization code
|
|
260
|
+
* 5. Exchange code for tokens
|
|
261
|
+
*/
|
|
262
|
+
export async function browserLogin() {
|
|
263
|
+
const codeVerifier = generateCodeVerifier();
|
|
264
|
+
const codeChallenge = generateCodeChallenge(codeVerifier);
|
|
265
|
+
const state = generateState();
|
|
266
|
+
// Build authorization URL (matches OpenAI's expected parameters)
|
|
267
|
+
const params = new URLSearchParams({
|
|
268
|
+
response_type: "code",
|
|
269
|
+
client_id: CLIENT_ID,
|
|
270
|
+
redirect_uri: PKCE_REDIRECT_URI,
|
|
271
|
+
scope: PKCE_SCOPES,
|
|
272
|
+
code_challenge: codeChallenge,
|
|
273
|
+
code_challenge_method: "S256",
|
|
274
|
+
state,
|
|
275
|
+
id_token_add_organizations: "true",
|
|
276
|
+
codex_cli_simplified_flow: "true",
|
|
277
|
+
originator: "longeragent",
|
|
278
|
+
});
|
|
279
|
+
const authorizeUrl = `${AUTHORIZE_URL}?${params.toString()}`;
|
|
280
|
+
// Start callback server
|
|
281
|
+
const { promise: codePromise, server } = waitForCallback(state);
|
|
282
|
+
const cleanup = () => {
|
|
283
|
+
try {
|
|
284
|
+
server.closeAllConnections();
|
|
285
|
+
server.close();
|
|
286
|
+
}
|
|
287
|
+
catch { /* ignore */ }
|
|
288
|
+
};
|
|
289
|
+
try {
|
|
290
|
+
console.log();
|
|
291
|
+
if (isRemoteSession()) {
|
|
292
|
+
console.log(" Open this URL in your browser:");
|
|
293
|
+
console.log(` \x1b[94m${authorizeUrl}\x1b[0m`);
|
|
294
|
+
}
|
|
295
|
+
else {
|
|
296
|
+
console.log(" Opening browser for authentication...");
|
|
297
|
+
openBrowser(authorizeUrl);
|
|
298
|
+
console.log(` If the browser didn't open, visit:`);
|
|
299
|
+
console.log(` \x1b[94m${authorizeUrl}\x1b[0m`);
|
|
300
|
+
}
|
|
301
|
+
console.log();
|
|
302
|
+
console.log(" Waiting for authorization... (press Ctrl+C to cancel)");
|
|
303
|
+
// Wait for callback or timeout
|
|
304
|
+
let timeoutHandle;
|
|
305
|
+
const timeoutPromise = new Promise((_, reject) => {
|
|
306
|
+
timeoutHandle = setTimeout(() => reject(new Error("Login timed out after 15 minutes.")), AUTH_TIMEOUT_MS);
|
|
307
|
+
});
|
|
308
|
+
const code = await Promise.race([codePromise, timeoutPromise]);
|
|
309
|
+
clearTimeout(timeoutHandle);
|
|
310
|
+
cleanup();
|
|
311
|
+
// Exchange code for tokens
|
|
312
|
+
const { status, data } = await fetchForm(TOKEN_URL, {
|
|
313
|
+
grant_type: "authorization_code",
|
|
314
|
+
code,
|
|
315
|
+
redirect_uri: PKCE_REDIRECT_URI,
|
|
316
|
+
client_id: CLIENT_ID,
|
|
317
|
+
code_verifier: codeVerifier,
|
|
318
|
+
});
|
|
319
|
+
if (status !== 200) {
|
|
320
|
+
const detail = typeof data["error_description"] === "string"
|
|
321
|
+
? data["error_description"]
|
|
322
|
+
: `status ${status}`;
|
|
323
|
+
throw new Error(`Token exchange failed: ${detail}`);
|
|
324
|
+
}
|
|
325
|
+
const accessToken = String(data["access_token"] ?? "");
|
|
326
|
+
const refreshToken = String(data["refresh_token"] ?? "");
|
|
327
|
+
if (!accessToken) {
|
|
328
|
+
throw new Error("Token exchange did not return an access_token.");
|
|
329
|
+
}
|
|
330
|
+
return { access_token: accessToken, refresh_token: refreshToken };
|
|
331
|
+
}
|
|
332
|
+
catch (err) {
|
|
333
|
+
cleanup();
|
|
334
|
+
throw err;
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
// =============================================================================
|
|
338
|
+
// Device Code OAuth flow
|
|
339
|
+
// =============================================================================
|
|
340
|
+
/**
|
|
341
|
+
* Execute the Device Code OAuth login flow.
|
|
342
|
+
*
|
|
343
|
+
* 1. Request device code from OpenAI
|
|
344
|
+
* 2. Display user code and verification URL
|
|
345
|
+
* 3. Poll for authorization (up to 15 minutes)
|
|
346
|
+
* 4. Exchange authorization code for tokens
|
|
347
|
+
*/
|
|
348
|
+
export async function deviceCodeLogin() {
|
|
349
|
+
// Step 1: Request device code
|
|
350
|
+
let deviceData;
|
|
351
|
+
try {
|
|
352
|
+
const { status, data } = await fetchJson(DEVICE_CODE_URL, {
|
|
353
|
+
method: "POST",
|
|
354
|
+
headers: { "Content-Type": "application/json" },
|
|
355
|
+
body: JSON.stringify({ client_id: CLIENT_ID }),
|
|
356
|
+
});
|
|
357
|
+
if (status !== 200) {
|
|
358
|
+
throw new Error(`Device code request returned status ${status}.`);
|
|
359
|
+
}
|
|
360
|
+
deviceData = data;
|
|
361
|
+
}
|
|
362
|
+
catch (err) {
|
|
363
|
+
throw new Error(`Failed to request device code: ${err instanceof Error ? err.message : String(err)}`);
|
|
364
|
+
}
|
|
365
|
+
const userCode = String(deviceData["user_code"] ?? "");
|
|
366
|
+
const deviceAuthId = String(deviceData["device_auth_id"] ?? "");
|
|
367
|
+
const pollInterval = Math.max(3, Number(deviceData["interval"]) || 5);
|
|
368
|
+
if (!userCode || !deviceAuthId) {
|
|
369
|
+
throw new Error("Device code response missing required fields.");
|
|
370
|
+
}
|
|
371
|
+
// Step 2: Display user code
|
|
372
|
+
console.log();
|
|
373
|
+
console.log(" To continue, follow these steps:");
|
|
374
|
+
console.log();
|
|
375
|
+
console.log(` 1. Open this URL in your browser:`);
|
|
376
|
+
console.log(` \x1b[94m${DEVICE_VERIFY_URL}\x1b[0m`);
|
|
377
|
+
console.log();
|
|
378
|
+
console.log(` 2. Enter this code:`);
|
|
379
|
+
console.log(` \x1b[94m${userCode}\x1b[0m`);
|
|
380
|
+
console.log();
|
|
381
|
+
console.log(" Waiting for sign-in... (press Ctrl+C to cancel)");
|
|
382
|
+
// Step 3: Poll for authorization code
|
|
383
|
+
const deadline = Date.now() + AUTH_TIMEOUT_MS;
|
|
384
|
+
let codeResp = null;
|
|
385
|
+
while (Date.now() < deadline) {
|
|
386
|
+
await new Promise((r) => setTimeout(r, pollInterval * 1000));
|
|
387
|
+
try {
|
|
388
|
+
const { status, data } = await fetchJson(DEVICE_POLL_URL, {
|
|
389
|
+
method: "POST",
|
|
390
|
+
headers: { "Content-Type": "application/json" },
|
|
391
|
+
body: JSON.stringify({
|
|
392
|
+
device_auth_id: deviceAuthId,
|
|
393
|
+
user_code: userCode,
|
|
394
|
+
}),
|
|
395
|
+
});
|
|
396
|
+
if (status === 200) {
|
|
397
|
+
codeResp = data;
|
|
398
|
+
break;
|
|
399
|
+
}
|
|
400
|
+
else if (status === 403 || status === 404) {
|
|
401
|
+
continue;
|
|
402
|
+
}
|
|
403
|
+
else {
|
|
404
|
+
throw new Error(`Device auth polling returned status ${status}.`);
|
|
405
|
+
}
|
|
406
|
+
}
|
|
407
|
+
catch (err) {
|
|
408
|
+
if (err instanceof Error && err.name === "AbortError") {
|
|
409
|
+
continue;
|
|
410
|
+
}
|
|
411
|
+
throw err;
|
|
412
|
+
}
|
|
413
|
+
}
|
|
414
|
+
if (codeResp === null) {
|
|
415
|
+
throw new Error("Login timed out after 15 minutes.");
|
|
416
|
+
}
|
|
417
|
+
// Step 4: Exchange authorization code for tokens
|
|
418
|
+
const authorizationCode = String(codeResp["authorization_code"] ?? "");
|
|
419
|
+
const codeVerifier = String(codeResp["code_verifier"] ?? "");
|
|
420
|
+
if (!authorizationCode || !codeVerifier) {
|
|
421
|
+
throw new Error("Device auth response missing authorization_code or code_verifier.");
|
|
422
|
+
}
|
|
423
|
+
let tokenData;
|
|
424
|
+
try {
|
|
425
|
+
const { status, data } = await fetchForm(TOKEN_URL, {
|
|
426
|
+
grant_type: "authorization_code",
|
|
427
|
+
code: authorizationCode,
|
|
428
|
+
redirect_uri: DEVICE_REDIRECT_URI,
|
|
429
|
+
client_id: CLIENT_ID,
|
|
430
|
+
code_verifier: codeVerifier,
|
|
431
|
+
});
|
|
432
|
+
if (status !== 200) {
|
|
433
|
+
throw new Error(`Token exchange returned status ${status}.`);
|
|
434
|
+
}
|
|
435
|
+
tokenData = data;
|
|
436
|
+
}
|
|
437
|
+
catch (err) {
|
|
438
|
+
throw new Error(`Token exchange failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
439
|
+
}
|
|
440
|
+
const accessToken = String(tokenData["access_token"] ?? "");
|
|
441
|
+
const refreshToken = String(tokenData["refresh_token"] ?? "");
|
|
442
|
+
if (!accessToken) {
|
|
443
|
+
throw new Error("Token exchange did not return an access_token.");
|
|
444
|
+
}
|
|
445
|
+
return { access_token: accessToken, refresh_token: refreshToken };
|
|
446
|
+
}
|
|
447
|
+
// =============================================================================
|
|
448
|
+
// Token refresh
|
|
449
|
+
// =============================================================================
|
|
450
|
+
export async function refreshAccessToken(refreshToken) {
|
|
451
|
+
const { status, data } = await fetchForm(TOKEN_URL, {
|
|
452
|
+
grant_type: "refresh_token",
|
|
453
|
+
refresh_token: refreshToken,
|
|
454
|
+
client_id: CLIENT_ID,
|
|
455
|
+
});
|
|
456
|
+
if (status !== 200) {
|
|
457
|
+
const errDesc = typeof data["error_description"] === "string"
|
|
458
|
+
? data["error_description"]
|
|
459
|
+
: typeof data["message"] === "string"
|
|
460
|
+
? data["message"]
|
|
461
|
+
: `status ${status}`;
|
|
462
|
+
const errCode = typeof data["error"] === "string" ? data["error"] : "";
|
|
463
|
+
const reloginHint = errCode === "invalid_grant" || errCode === "invalid_token"
|
|
464
|
+
? " Run 'longeragent oauth' to re-authenticate."
|
|
465
|
+
: "";
|
|
466
|
+
throw new Error(`Token refresh failed: ${errDesc}.${reloginHint}`);
|
|
467
|
+
}
|
|
468
|
+
const accessToken = String(data["access_token"] ?? "");
|
|
469
|
+
if (!accessToken) {
|
|
470
|
+
throw new Error("Token refresh response missing access_token. Run 'longeragent oauth' to re-authenticate.");
|
|
471
|
+
}
|
|
472
|
+
const newRefreshToken = typeof data["refresh_token"] === "string" && data["refresh_token"]
|
|
473
|
+
? String(data["refresh_token"])
|
|
474
|
+
: refreshToken;
|
|
475
|
+
const tokens = {
|
|
476
|
+
access_token: accessToken,
|
|
477
|
+
refresh_token: newRefreshToken,
|
|
478
|
+
};
|
|
479
|
+
saveOAuthTokens(tokens);
|
|
480
|
+
return tokens;
|
|
481
|
+
}
|
|
482
|
+
// =============================================================================
|
|
483
|
+
// Composite: ensure fresh token
|
|
484
|
+
// =============================================================================
|
|
485
|
+
export async function ensureFreshToken() {
|
|
486
|
+
const store = loadAuthStore();
|
|
487
|
+
const codex = store.openai_codex;
|
|
488
|
+
if (!codex ||
|
|
489
|
+
typeof codex.access_token !== "string" ||
|
|
490
|
+
!codex.access_token.trim() ||
|
|
491
|
+
typeof codex.refresh_token !== "string" ||
|
|
492
|
+
!codex.refresh_token.trim()) {
|
|
493
|
+
throw new Error("No OpenAI OAuth credentials stored. Run 'longeragent oauth' to log in.");
|
|
494
|
+
}
|
|
495
|
+
if (isTokenExpiring(codex.access_token)) {
|
|
496
|
+
const refreshed = await refreshAccessToken(codex.refresh_token);
|
|
497
|
+
return refreshed.access_token;
|
|
498
|
+
}
|
|
499
|
+
return codex.access_token;
|
|
500
|
+
}
|
|
501
|
+
// =============================================================================
|
|
502
|
+
// CLI command: `longeragent oauth [action]`
|
|
503
|
+
// =============================================================================
|
|
504
|
+
function isUserCancel(err) {
|
|
505
|
+
if (!err || typeof err !== "object")
|
|
506
|
+
return false;
|
|
507
|
+
return (err.name === "ExitPromptError" ||
|
|
508
|
+
err.code === "ERR_USE_AFTER_CLOSE");
|
|
509
|
+
}
|
|
510
|
+
async function performLogin() {
|
|
511
|
+
const method = await select({
|
|
512
|
+
message: "Login method",
|
|
513
|
+
choices: [
|
|
514
|
+
{ name: "Browser login (recommended)", value: "browser" },
|
|
515
|
+
{ name: "Device code (SSH / headless)", value: "device" },
|
|
516
|
+
],
|
|
517
|
+
});
|
|
518
|
+
if (method === "browser") {
|
|
519
|
+
return browserLogin();
|
|
520
|
+
}
|
|
521
|
+
return deviceCodeLogin();
|
|
522
|
+
}
|
|
523
|
+
async function oauthLogin() {
|
|
524
|
+
// Check if already logged in
|
|
525
|
+
if (hasOAuthTokens()) {
|
|
526
|
+
const token = readOAuthAccessToken();
|
|
527
|
+
const expiry = getTokenExpiry(token);
|
|
528
|
+
const expiryStr = expiry ? expiry.toLocaleString() : "unknown";
|
|
529
|
+
const expired = expiry ? expiry.getTime() < Date.now() : false;
|
|
530
|
+
const tokenStatus = expired ? "expired" : "valid";
|
|
531
|
+
console.log(` Existing login found (token ${tokenStatus}, expires: ${expiryStr})`);
|
|
532
|
+
try {
|
|
533
|
+
const reLogin = await confirm({
|
|
534
|
+
message: "Re-authenticate with a new login?",
|
|
535
|
+
default: false,
|
|
536
|
+
});
|
|
537
|
+
if (!reLogin) {
|
|
538
|
+
if (expired || isTokenExpiring(token)) {
|
|
539
|
+
console.log(" Refreshing token...");
|
|
540
|
+
try {
|
|
541
|
+
await ensureFreshToken();
|
|
542
|
+
console.log(" Token refreshed successfully.");
|
|
543
|
+
}
|
|
544
|
+
catch (err) {
|
|
545
|
+
console.error(` Token refresh failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
546
|
+
console.log(" Please re-authenticate.");
|
|
547
|
+
}
|
|
548
|
+
}
|
|
549
|
+
else {
|
|
550
|
+
console.log(" Using existing login.");
|
|
551
|
+
}
|
|
552
|
+
return;
|
|
553
|
+
}
|
|
554
|
+
}
|
|
555
|
+
catch (err) {
|
|
556
|
+
if (isUserCancel(err)) {
|
|
557
|
+
console.log("\n Cancelled.");
|
|
558
|
+
return;
|
|
559
|
+
}
|
|
560
|
+
throw err;
|
|
561
|
+
}
|
|
562
|
+
}
|
|
563
|
+
const tokens = await performLogin();
|
|
564
|
+
saveOAuthTokens(tokens);
|
|
565
|
+
console.log();
|
|
566
|
+
console.log(" Login successful!");
|
|
567
|
+
console.log(" OAuth tokens saved to ~/.longeragent/auth.json");
|
|
568
|
+
console.log();
|
|
569
|
+
console.log(" To use with LongerAgent, run 'longeragent init' and select");
|
|
570
|
+
console.log(" 'OpenAI (ChatGPT Login)', or add to your config.yaml:");
|
|
571
|
+
console.log();
|
|
572
|
+
console.log(" my-codex:");
|
|
573
|
+
console.log(" provider: openai-codex");
|
|
574
|
+
console.log(" model: gpt-5.3-codex");
|
|
575
|
+
console.log(" api_key: \"oauth:openai-codex\"");
|
|
576
|
+
console.log();
|
|
577
|
+
}
|
|
578
|
+
function oauthStatus() {
|
|
579
|
+
if (!hasOAuthTokens()) {
|
|
580
|
+
console.log(" Not logged in.");
|
|
581
|
+
console.log(" Run 'longeragent oauth' to log in with your ChatGPT account.");
|
|
582
|
+
return;
|
|
583
|
+
}
|
|
584
|
+
const token = readOAuthAccessToken();
|
|
585
|
+
const expiry = getTokenExpiry(token);
|
|
586
|
+
const expiryStr = expiry ? expiry.toLocaleString() : "unknown";
|
|
587
|
+
const expired = expiry ? expiry.getTime() < Date.now() : false;
|
|
588
|
+
const expiring = isTokenExpiring(token);
|
|
589
|
+
const store = loadAuthStore();
|
|
590
|
+
const lastRefresh = store.openai_codex?.last_refresh ?? "unknown";
|
|
591
|
+
console.log(" OpenAI OAuth Status");
|
|
592
|
+
console.log(` Status: ${expired ? "expired" : expiring ? "expiring soon" : "active"}`);
|
|
593
|
+
console.log(` Expires: ${expiryStr}`);
|
|
594
|
+
console.log(` Last refresh: ${lastRefresh}`);
|
|
595
|
+
console.log(` Auth store: ${authStorePath()}`);
|
|
596
|
+
if (expired) {
|
|
597
|
+
console.log();
|
|
598
|
+
console.log(" Token has expired. Run 'longeragent oauth' to re-authenticate.");
|
|
599
|
+
}
|
|
600
|
+
else if (expiring) {
|
|
601
|
+
console.log();
|
|
602
|
+
console.log(" Token will expire soon. It will be auto-refreshed on next use.");
|
|
603
|
+
}
|
|
604
|
+
}
|
|
605
|
+
function oauthLogout() {
|
|
606
|
+
if (!hasOAuthTokens()) {
|
|
607
|
+
console.log(" Not logged in — nothing to clear.");
|
|
608
|
+
return;
|
|
609
|
+
}
|
|
610
|
+
clearOAuthTokens();
|
|
611
|
+
console.log(" OAuth tokens cleared.");
|
|
612
|
+
}
|
|
613
|
+
/**
|
|
614
|
+
* Entry point for `longeragent oauth [action]`.
|
|
615
|
+
*/
|
|
616
|
+
export async function oauthCommand(action) {
|
|
617
|
+
const normalized = (action ?? "").trim().toLowerCase();
|
|
618
|
+
console.log();
|
|
619
|
+
console.log(" ╔══════════════════════════════════════╗");
|
|
620
|
+
console.log(" ║ OpenAI ChatGPT OAuth Login ║");
|
|
621
|
+
console.log(" ╚══════════════════════════════════════╝");
|
|
622
|
+
console.log();
|
|
623
|
+
switch (normalized) {
|
|
624
|
+
case "":
|
|
625
|
+
case "login":
|
|
626
|
+
await oauthLogin();
|
|
627
|
+
break;
|
|
628
|
+
case "status":
|
|
629
|
+
oauthStatus();
|
|
630
|
+
break;
|
|
631
|
+
case "logout":
|
|
632
|
+
oauthLogout();
|
|
633
|
+
break;
|
|
634
|
+
default:
|
|
635
|
+
console.log(` Unknown action: ${normalized}`);
|
|
636
|
+
console.log(" Usage: longeragent oauth [login|status|logout]");
|
|
637
|
+
break;
|
|
638
|
+
}
|
|
639
|
+
}
|
|
640
|
+
//# sourceMappingURL=openai-oauth.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"openai-oauth.js","sourceRoot":"","sources":["../../src/auth/openai-oauth.ts"],"names":[],"mappings":"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"}
|