amai 0.0.17 → 0.0.18
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/dist/cli.cjs +531 -94
- package/dist/cli.js +529 -92
- package/dist/lib/daemon-entry.cjs +477 -70
- package/dist/lib/daemon-entry.js +475 -68
- package/dist/server.cjs +414 -7
- package/dist/server.js +415 -8
- package/package.json +1 -1
package/dist/cli.cjs
CHANGED
|
@@ -5,7 +5,7 @@ var pc5 = require('picocolors');
|
|
|
5
5
|
var WebSocket = require('ws');
|
|
6
6
|
var zod = require('zod');
|
|
7
7
|
var path10 = require('path');
|
|
8
|
-
var
|
|
8
|
+
var fs10 = require('fs');
|
|
9
9
|
var os3 = require('os');
|
|
10
10
|
var fs8 = require('fs/promises');
|
|
11
11
|
var hono = require('hono');
|
|
@@ -22,7 +22,7 @@ function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
|
|
|
22
22
|
var pc5__default = /*#__PURE__*/_interopDefault(pc5);
|
|
23
23
|
var WebSocket__default = /*#__PURE__*/_interopDefault(WebSocket);
|
|
24
24
|
var path10__default = /*#__PURE__*/_interopDefault(path10);
|
|
25
|
-
var
|
|
25
|
+
var fs10__default = /*#__PURE__*/_interopDefault(fs10);
|
|
26
26
|
var os3__default = /*#__PURE__*/_interopDefault(os3);
|
|
27
27
|
var fs8__default = /*#__PURE__*/_interopDefault(fs8);
|
|
28
28
|
var readline__default = /*#__PURE__*/_interopDefault(readline);
|
|
@@ -52,11 +52,11 @@ function isPathWithinProject(filePath, projectCwd) {
|
|
|
52
52
|
}
|
|
53
53
|
function safeRealpath(p) {
|
|
54
54
|
try {
|
|
55
|
-
return
|
|
55
|
+
return fs10__default.default.realpathSync(p);
|
|
56
56
|
} catch {
|
|
57
57
|
const parent = path10__default.default.dirname(p);
|
|
58
58
|
try {
|
|
59
|
-
const realParent =
|
|
59
|
+
const realParent = fs10__default.default.realpathSync(parent);
|
|
60
60
|
return path10__default.default.join(realParent, path10__default.default.basename(p));
|
|
61
61
|
} catch {
|
|
62
62
|
return path10__default.default.resolve(p);
|
|
@@ -353,16 +353,16 @@ var Diff = class {
|
|
|
353
353
|
}
|
|
354
354
|
}
|
|
355
355
|
}
|
|
356
|
-
addToPath(
|
|
357
|
-
const last =
|
|
356
|
+
addToPath(path17, added, removed, oldPosInc, options) {
|
|
357
|
+
const last = path17.lastComponent;
|
|
358
358
|
if (last && !options.oneChangePerToken && last.added === added && last.removed === removed) {
|
|
359
359
|
return {
|
|
360
|
-
oldPos:
|
|
360
|
+
oldPos: path17.oldPos + oldPosInc,
|
|
361
361
|
lastComponent: { count: last.count + 1, added, removed, previousComponent: last.previousComponent }
|
|
362
362
|
};
|
|
363
363
|
} else {
|
|
364
364
|
return {
|
|
365
|
-
oldPos:
|
|
365
|
+
oldPos: path17.oldPos + oldPosInc,
|
|
366
366
|
lastComponent: { count: 1, added, removed, previousComponent: last }
|
|
367
367
|
};
|
|
368
368
|
}
|
|
@@ -518,7 +518,7 @@ function calculateDiffStats(oldContent, newContent) {
|
|
|
518
518
|
return { linesAdded, linesRemoved };
|
|
519
519
|
}
|
|
520
520
|
|
|
521
|
-
// src/tools/
|
|
521
|
+
// src/tools/stringReplace.ts
|
|
522
522
|
zod.z.object({
|
|
523
523
|
file_path: zod.z.string().describe("The path to the file you want to search and replace in. You can use either a relative path in the workspace or an absolute path. If an absolute path is provided, it will be preserved as is"),
|
|
524
524
|
new_string: zod.z.string().describe("The edited text to replace the old_string (must be different from the old_string)"),
|
|
@@ -628,8 +628,8 @@ var apply_patch = async function(input, projectCwd) {
|
|
|
628
628
|
};
|
|
629
629
|
}
|
|
630
630
|
};
|
|
631
|
-
var DEFAULT_SERVER_URL = "
|
|
632
|
-
var CLIENT_ID = "
|
|
631
|
+
var DEFAULT_SERVER_URL = "ws://localhost:3000";
|
|
632
|
+
var CLIENT_ID = "client_01K4Y8A5Q3FYGXD362BJQ6AGYD";
|
|
633
633
|
var AMA_DIR = path10__default.default.join(os3__default.default.homedir(), ".amai");
|
|
634
634
|
var CODE_DIR = path10__default.default.join(AMA_DIR, "code");
|
|
635
635
|
var STORAGE_DIR = path10__default.default.join(AMA_DIR, "storage");
|
|
@@ -804,7 +804,7 @@ async function getRipgrepPath() {
|
|
|
804
804
|
"/usr/bin/rg"
|
|
805
805
|
];
|
|
806
806
|
for (const rgPath of paths) {
|
|
807
|
-
if (
|
|
807
|
+
if (fs10__default.default.existsSync(rgPath)) {
|
|
808
808
|
_cachedRgPath = rgPath;
|
|
809
809
|
return rgPath;
|
|
810
810
|
}
|
|
@@ -824,7 +824,7 @@ async function getMtimesBatched(files) {
|
|
|
824
824
|
return { path: filePath, mtime };
|
|
825
825
|
})
|
|
826
826
|
);
|
|
827
|
-
results.forEach(({ path:
|
|
827
|
+
results.forEach(({ path: path17, mtime }) => mtimeMap.set(path17, mtime));
|
|
828
828
|
}
|
|
829
829
|
return mtimeMap;
|
|
830
830
|
}
|
|
@@ -853,7 +853,7 @@ var grepTool = async function(input, projectCwd) {
|
|
|
853
853
|
}
|
|
854
854
|
}
|
|
855
855
|
}
|
|
856
|
-
if (!
|
|
856
|
+
if (!fs10__default.default.existsSync(searchDir)) {
|
|
857
857
|
return {
|
|
858
858
|
success: false,
|
|
859
859
|
message: `Directory not found: ${searchDir}`,
|
|
@@ -1036,7 +1036,7 @@ var globTool = async function(input, projectCwd) {
|
|
|
1036
1036
|
try {
|
|
1037
1037
|
const basePath = projectCwd || process.cwd();
|
|
1038
1038
|
const searchPath = inputPath ? resolveProjectPath(inputPath, basePath) : basePath;
|
|
1039
|
-
if (!
|
|
1039
|
+
if (!fs10__default.default.existsSync(searchPath)) {
|
|
1040
1040
|
return {
|
|
1041
1041
|
success: false,
|
|
1042
1042
|
message: `Directory not found: ${searchPath}`,
|
|
@@ -1240,14 +1240,14 @@ var list = async function(input, projectCwd) {
|
|
|
1240
1240
|
};
|
|
1241
1241
|
}
|
|
1242
1242
|
}
|
|
1243
|
-
if (!
|
|
1243
|
+
if (!fs10__default.default.existsSync(absolutePath)) {
|
|
1244
1244
|
return {
|
|
1245
1245
|
success: false,
|
|
1246
1246
|
message: `Directory not found: ${absolutePath}`,
|
|
1247
1247
|
error: "DIR_NOT_FOUND"
|
|
1248
1248
|
};
|
|
1249
1249
|
}
|
|
1250
|
-
const stats =
|
|
1250
|
+
const stats = fs10__default.default.statSync(absolutePath);
|
|
1251
1251
|
if (!stats.isDirectory()) {
|
|
1252
1252
|
return {
|
|
1253
1253
|
success: false,
|
|
@@ -1264,7 +1264,7 @@ var list = async function(input, projectCwd) {
|
|
|
1264
1264
|
}
|
|
1265
1265
|
let entries;
|
|
1266
1266
|
try {
|
|
1267
|
-
entries =
|
|
1267
|
+
entries = fs10__default.default.readdirSync(currentDir, { withFileTypes: true });
|
|
1268
1268
|
} catch {
|
|
1269
1269
|
return;
|
|
1270
1270
|
}
|
|
@@ -1379,10 +1379,10 @@ var CREDENTIALS_DIR = path10__default.default.join(os3__default.default.homedir(
|
|
|
1379
1379
|
var CREDENTIALS_PATH = path10__default.default.join(CREDENTIALS_DIR, "credentials.json");
|
|
1380
1380
|
function isAuthenticated() {
|
|
1381
1381
|
try {
|
|
1382
|
-
if (!
|
|
1382
|
+
if (!fs10__default.default.existsSync(CREDENTIALS_PATH)) {
|
|
1383
1383
|
return false;
|
|
1384
1384
|
}
|
|
1385
|
-
const raw =
|
|
1385
|
+
const raw = fs10__default.default.readFileSync(CREDENTIALS_PATH, "utf8");
|
|
1386
1386
|
const data = JSON.parse(raw);
|
|
1387
1387
|
return Boolean(data && data.access_token);
|
|
1388
1388
|
} catch {
|
|
@@ -1391,10 +1391,10 @@ function isAuthenticated() {
|
|
|
1391
1391
|
}
|
|
1392
1392
|
function saveTokens(tokens) {
|
|
1393
1393
|
try {
|
|
1394
|
-
if (!
|
|
1395
|
-
|
|
1394
|
+
if (!fs10__default.default.existsSync(CREDENTIALS_DIR)) {
|
|
1395
|
+
fs10__default.default.mkdirSync(CREDENTIALS_DIR, { recursive: true });
|
|
1396
1396
|
}
|
|
1397
|
-
|
|
1397
|
+
fs10__default.default.writeFileSync(
|
|
1398
1398
|
CREDENTIALS_PATH,
|
|
1399
1399
|
JSON.stringify(tokens, null, 2),
|
|
1400
1400
|
"utf8"
|
|
@@ -1405,18 +1405,18 @@ function saveTokens(tokens) {
|
|
|
1405
1405
|
}
|
|
1406
1406
|
function logout() {
|
|
1407
1407
|
try {
|
|
1408
|
-
if (
|
|
1409
|
-
|
|
1408
|
+
if (fs10__default.default.existsSync(CREDENTIALS_PATH)) {
|
|
1409
|
+
fs10__default.default.unlinkSync(CREDENTIALS_PATH);
|
|
1410
1410
|
}
|
|
1411
1411
|
} catch (error) {
|
|
1412
1412
|
console.error(pc5__default.default.red("Failed to logout"), error);
|
|
1413
1413
|
}
|
|
1414
1414
|
}
|
|
1415
1415
|
function getTokens() {
|
|
1416
|
-
if (!
|
|
1416
|
+
if (!fs10__default.default.existsSync(CREDENTIALS_PATH)) {
|
|
1417
1417
|
return null;
|
|
1418
1418
|
}
|
|
1419
|
-
const raw =
|
|
1419
|
+
const raw = fs10__default.default.readFileSync(CREDENTIALS_PATH, "utf8");
|
|
1420
1420
|
const data = JSON.parse(raw);
|
|
1421
1421
|
return data;
|
|
1422
1422
|
}
|
|
@@ -1515,10 +1515,10 @@ async function login() {
|
|
|
1515
1515
|
}
|
|
1516
1516
|
var getUserId = () => {
|
|
1517
1517
|
try {
|
|
1518
|
-
if (!
|
|
1518
|
+
if (!fs10__default.default.existsSync(CREDENTIALS_PATH)) {
|
|
1519
1519
|
return;
|
|
1520
1520
|
}
|
|
1521
|
-
const raw =
|
|
1521
|
+
const raw = fs10__default.default.readFileSync(CREDENTIALS_PATH, "utf8");
|
|
1522
1522
|
const data = JSON.parse(raw);
|
|
1523
1523
|
const fromUserObject = data.user?.id;
|
|
1524
1524
|
const fromTopLevel = data.sub ?? data.user_id;
|
|
@@ -1706,14 +1706,14 @@ var ProjectRegistry = class {
|
|
|
1706
1706
|
}
|
|
1707
1707
|
load() {
|
|
1708
1708
|
try {
|
|
1709
|
-
if (
|
|
1710
|
-
const data =
|
|
1709
|
+
if (fs10__default.default.existsSync(REGISTRY_FILE)) {
|
|
1710
|
+
const data = fs10__default.default.readFileSync(REGISTRY_FILE, "utf8");
|
|
1711
1711
|
const parsed = JSON.parse(data);
|
|
1712
1712
|
if (!Array.isArray(parsed)) {
|
|
1713
1713
|
console.error("Invalid project registry format: expected array, got", typeof parsed);
|
|
1714
1714
|
const backupFile = REGISTRY_FILE + ".backup." + Date.now();
|
|
1715
|
-
|
|
1716
|
-
|
|
1715
|
+
fs10__default.default.copyFileSync(REGISTRY_FILE, backupFile);
|
|
1716
|
+
fs10__default.default.unlinkSync(REGISTRY_FILE);
|
|
1717
1717
|
return;
|
|
1718
1718
|
}
|
|
1719
1719
|
const projects = parsed;
|
|
@@ -1726,11 +1726,11 @@ var ProjectRegistry = class {
|
|
|
1726
1726
|
}
|
|
1727
1727
|
} catch (error) {
|
|
1728
1728
|
console.error("Failed to load project registry:", error);
|
|
1729
|
-
if (
|
|
1729
|
+
if (fs10__default.default.existsSync(REGISTRY_FILE)) {
|
|
1730
1730
|
try {
|
|
1731
1731
|
const backupFile = REGISTRY_FILE + ".backup." + Date.now();
|
|
1732
|
-
|
|
1733
|
-
|
|
1732
|
+
fs10__default.default.copyFileSync(REGISTRY_FILE, backupFile);
|
|
1733
|
+
fs10__default.default.unlinkSync(REGISTRY_FILE);
|
|
1734
1734
|
console.log("Corrupted registry file backed up and removed. Starting fresh.");
|
|
1735
1735
|
} catch (backupError) {
|
|
1736
1736
|
}
|
|
@@ -1739,11 +1739,11 @@ var ProjectRegistry = class {
|
|
|
1739
1739
|
}
|
|
1740
1740
|
save() {
|
|
1741
1741
|
try {
|
|
1742
|
-
if (!
|
|
1743
|
-
|
|
1742
|
+
if (!fs10__default.default.existsSync(AMA_DIR)) {
|
|
1743
|
+
fs10__default.default.mkdirSync(AMA_DIR, { recursive: true });
|
|
1744
1744
|
}
|
|
1745
1745
|
const projects = Array.from(this.projects.values());
|
|
1746
|
-
|
|
1746
|
+
fs10__default.default.writeFileSync(REGISTRY_FILE, JSON.stringify(projects, null, 2), "utf8");
|
|
1747
1747
|
} catch (error) {
|
|
1748
1748
|
console.error("Failed to save project registry:", error);
|
|
1749
1749
|
}
|
|
@@ -1783,7 +1783,7 @@ var ProjectRegistry = class {
|
|
|
1783
1783
|
var projectRegistry = new ProjectRegistry();
|
|
1784
1784
|
var ignoreFiles = ["node_modules", ".git", ".next", ".env", ".env.local", ".env.development.local", ".env.test.local", ".env.production.local", ".output", ".turbo", ".vercel", ".next", ".tanstack", ".nitro", ".wrangler", ".alchemy", ".coverage", ".nyc_output", ".cache", "tmp", "temp", ".idea", ".vscode", ".zig-cache", "zig-out", ".coverage", "coverage", "logs", ".venv", "venv", "env", ".next", ".turbo", ".vercel", ".output", ".tanstack", ".nitro", ".wrangler", ".alchemy", ".coverage", ".nyc_output", ".cache", "tmp", "temp", ".idea", ".vscode", ".zig-cache", "zig-out", ".coverage", "coverage", "logs", ".venv", "venv", "env"];
|
|
1785
1785
|
var getContext = (dir, base = dir, allFiles = []) => {
|
|
1786
|
-
const filePath =
|
|
1786
|
+
const filePath = fs10.readdirSync(dir, { withFileTypes: true });
|
|
1787
1787
|
for (const file of filePath) {
|
|
1788
1788
|
if (ignoreFiles.includes(file.name)) continue;
|
|
1789
1789
|
const fullPath = path10__default.default.join(dir, file.name);
|
|
@@ -1812,7 +1812,7 @@ function getWorkspaceStoragePath(ide) {
|
|
|
1812
1812
|
} else {
|
|
1813
1813
|
const capitalizedPath = path10__default.default.join(HOME, ".config", appName, "User", "workspaceStorage");
|
|
1814
1814
|
const lowercasePath = path10__default.default.join(HOME, ".config", appNameLower, "User", "workspaceStorage");
|
|
1815
|
-
if (
|
|
1815
|
+
if (fs10__default.default.existsSync(capitalizedPath)) {
|
|
1816
1816
|
return capitalizedPath;
|
|
1817
1817
|
}
|
|
1818
1818
|
return lowercasePath;
|
|
@@ -1821,16 +1821,16 @@ function getWorkspaceStoragePath(ide) {
|
|
|
1821
1821
|
function scanWorkspaceStorage(ide) {
|
|
1822
1822
|
const projects = [];
|
|
1823
1823
|
const storagePath = getWorkspaceStoragePath(ide);
|
|
1824
|
-
if (!
|
|
1824
|
+
if (!fs10__default.default.existsSync(storagePath)) {
|
|
1825
1825
|
return projects;
|
|
1826
1826
|
}
|
|
1827
1827
|
try {
|
|
1828
|
-
const workspaces =
|
|
1828
|
+
const workspaces = fs10__default.default.readdirSync(storagePath);
|
|
1829
1829
|
for (const workspace of workspaces) {
|
|
1830
1830
|
const workspaceJsonPath = path10__default.default.join(storagePath, workspace, "workspace.json");
|
|
1831
|
-
if (
|
|
1831
|
+
if (fs10__default.default.existsSync(workspaceJsonPath)) {
|
|
1832
1832
|
try {
|
|
1833
|
-
const content =
|
|
1833
|
+
const content = fs10__default.default.readFileSync(workspaceJsonPath, "utf-8");
|
|
1834
1834
|
const data = JSON.parse(content);
|
|
1835
1835
|
if (data.folder && typeof data.folder === "string") {
|
|
1836
1836
|
let projectPath = data.folder;
|
|
@@ -1838,7 +1838,7 @@ function scanWorkspaceStorage(ide) {
|
|
|
1838
1838
|
projectPath = projectPath.replace("file://", "");
|
|
1839
1839
|
projectPath = decodeURIComponent(projectPath);
|
|
1840
1840
|
}
|
|
1841
|
-
if (
|
|
1841
|
+
if (fs10__default.default.existsSync(projectPath) && fs10__default.default.statSync(projectPath).isDirectory()) {
|
|
1842
1842
|
projects.push({
|
|
1843
1843
|
name: path10__default.default.basename(projectPath),
|
|
1844
1844
|
path: projectPath,
|
|
@@ -1862,11 +1862,11 @@ var scanIdeProjects = async () => {
|
|
|
1862
1862
|
const seenPaths = /* @__PURE__ */ new Set();
|
|
1863
1863
|
const addProject = (projectPath, ide) => {
|
|
1864
1864
|
try {
|
|
1865
|
-
const resolvedPath =
|
|
1866
|
-
if (
|
|
1865
|
+
const resolvedPath = fs10__default.default.realpathSync(projectPath);
|
|
1866
|
+
if (fs10__default.default.existsSync(resolvedPath) && fs10__default.default.statSync(resolvedPath).isDirectory() && !seenPaths.has(resolvedPath)) {
|
|
1867
1867
|
const isIdeProjectsDir = Object.values(IDE_PROJECTS_PATHS).some((ideDir) => {
|
|
1868
1868
|
try {
|
|
1869
|
-
return
|
|
1869
|
+
return fs10__default.default.realpathSync(ideDir) === resolvedPath;
|
|
1870
1870
|
} catch {
|
|
1871
1871
|
return false;
|
|
1872
1872
|
}
|
|
@@ -1893,30 +1893,30 @@ var scanIdeProjects = async () => {
|
|
|
1893
1893
|
}
|
|
1894
1894
|
for (const [ide, dirPath] of Object.entries(IDE_PROJECTS_PATHS)) {
|
|
1895
1895
|
if (ide === "cursor" || ide === "vscode") continue;
|
|
1896
|
-
if (
|
|
1897
|
-
const projects =
|
|
1896
|
+
if (fs10__default.default.existsSync(dirPath)) {
|
|
1897
|
+
const projects = fs10__default.default.readdirSync(dirPath);
|
|
1898
1898
|
projects.forEach((project) => {
|
|
1899
1899
|
const projectPath = path10__default.default.join(dirPath, project);
|
|
1900
1900
|
try {
|
|
1901
|
-
const stats =
|
|
1901
|
+
const stats = fs10__default.default.lstatSync(projectPath);
|
|
1902
1902
|
let actualPath = null;
|
|
1903
1903
|
if (stats.isSymbolicLink()) {
|
|
1904
|
-
actualPath =
|
|
1904
|
+
actualPath = fs10__default.default.realpathSync(projectPath);
|
|
1905
1905
|
} else if (stats.isFile()) {
|
|
1906
1906
|
try {
|
|
1907
|
-
let content =
|
|
1907
|
+
let content = fs10__default.default.readFileSync(projectPath, "utf-8").trim();
|
|
1908
1908
|
if (content.startsWith("~/") || content === "~") {
|
|
1909
1909
|
content = content.replace(/^~/, HOME);
|
|
1910
1910
|
}
|
|
1911
1911
|
const resolvedContent = path10__default.default.isAbsolute(content) ? content : path10__default.default.resolve(path10__default.default.dirname(projectPath), content);
|
|
1912
|
-
if (
|
|
1913
|
-
actualPath =
|
|
1912
|
+
if (fs10__default.default.existsSync(resolvedContent) && fs10__default.default.statSync(resolvedContent).isDirectory()) {
|
|
1913
|
+
actualPath = fs10__default.default.realpathSync(resolvedContent);
|
|
1914
1914
|
}
|
|
1915
1915
|
} catch {
|
|
1916
1916
|
return;
|
|
1917
1917
|
}
|
|
1918
1918
|
} else if (stats.isDirectory()) {
|
|
1919
|
-
actualPath =
|
|
1919
|
+
actualPath = fs10__default.default.realpathSync(projectPath);
|
|
1920
1920
|
}
|
|
1921
1921
|
if (actualPath) {
|
|
1922
1922
|
addProject(actualPath, ide);
|
|
@@ -2181,6 +2181,396 @@ var Snapshot;
|
|
|
2181
2181
|
return path10__default.default.join(Global.Path.data, "snapshot", projectId);
|
|
2182
2182
|
}
|
|
2183
2183
|
})(Snapshot || (Snapshot = {}));
|
|
2184
|
+
var CLIENT_ID2 = "app_EMoamEEZ73f0CkXaXp7hrann";
|
|
2185
|
+
var ISSUER = "https://auth.openai.com";
|
|
2186
|
+
var OAUTH_PORT = 1455;
|
|
2187
|
+
var CREDENTIALS_PATH2 = path10__default.default.join(AMA_DIR, "codex-credentials.json");
|
|
2188
|
+
var CALLBACK_PATH = "/auth/callback";
|
|
2189
|
+
var OAUTH_TIMEOUT_MS = 5 * 60 * 1e3;
|
|
2190
|
+
var REFRESH_BUFFER_MS = 60 * 1e3;
|
|
2191
|
+
var oauthServer;
|
|
2192
|
+
var pendingOAuth;
|
|
2193
|
+
var HTML_SUCCESS = `<!doctype html>
|
|
2194
|
+
<html>
|
|
2195
|
+
<head>
|
|
2196
|
+
<title>amai - Codex Authorization Successful</title>
|
|
2197
|
+
<style>
|
|
2198
|
+
body {
|
|
2199
|
+
font-family:
|
|
2200
|
+
system-ui,
|
|
2201
|
+
-apple-system,
|
|
2202
|
+
sans-serif;
|
|
2203
|
+
display: flex;
|
|
2204
|
+
justify-content: center;
|
|
2205
|
+
align-items: center;
|
|
2206
|
+
height: 100vh;
|
|
2207
|
+
margin: 0;
|
|
2208
|
+
background: #131010;
|
|
2209
|
+
color: #f1ecec;
|
|
2210
|
+
}
|
|
2211
|
+
.container {
|
|
2212
|
+
text-align: center;
|
|
2213
|
+
padding: 2rem;
|
|
2214
|
+
}
|
|
2215
|
+
h1 {
|
|
2216
|
+
color: #f1ecec;
|
|
2217
|
+
margin-bottom: 1rem;
|
|
2218
|
+
}
|
|
2219
|
+
p {
|
|
2220
|
+
color: #b7b1b1;
|
|
2221
|
+
}
|
|
2222
|
+
</style>
|
|
2223
|
+
</head>
|
|
2224
|
+
<body>
|
|
2225
|
+
<div class="container">
|
|
2226
|
+
<h1>Authorization Successful</h1>
|
|
2227
|
+
<p>You can close this window and return to ama.</p>
|
|
2228
|
+
</div>
|
|
2229
|
+
<script>
|
|
2230
|
+
setTimeout(() => window.close(), 2000)
|
|
2231
|
+
</script>
|
|
2232
|
+
</body>
|
|
2233
|
+
</html>`;
|
|
2234
|
+
var HTML_ERROR = (error) => `<!doctype html>
|
|
2235
|
+
<html>
|
|
2236
|
+
<head>
|
|
2237
|
+
<title>amai - Codex Authorization Failed</title>
|
|
2238
|
+
<style>
|
|
2239
|
+
body {
|
|
2240
|
+
font-family:
|
|
2241
|
+
system-ui,
|
|
2242
|
+
-apple-system,
|
|
2243
|
+
sans-serif;
|
|
2244
|
+
display: flex;
|
|
2245
|
+
justify-content: center;
|
|
2246
|
+
align-items: center;
|
|
2247
|
+
height: 100vh;
|
|
2248
|
+
margin: 0;
|
|
2249
|
+
background: #131010;
|
|
2250
|
+
color: #f1ecec;
|
|
2251
|
+
}
|
|
2252
|
+
.container {
|
|
2253
|
+
text-align: center;
|
|
2254
|
+
padding: 2rem;
|
|
2255
|
+
}
|
|
2256
|
+
h1 {
|
|
2257
|
+
color: #fc533a;
|
|
2258
|
+
margin-bottom: 1rem;
|
|
2259
|
+
}
|
|
2260
|
+
p {
|
|
2261
|
+
color: #b7b1b1;
|
|
2262
|
+
}
|
|
2263
|
+
.error {
|
|
2264
|
+
color: #ff917b;
|
|
2265
|
+
font-family: monospace;
|
|
2266
|
+
margin-top: 1rem;
|
|
2267
|
+
padding: 1rem;
|
|
2268
|
+
background: #3c140d;
|
|
2269
|
+
border-radius: 0.5rem;
|
|
2270
|
+
}
|
|
2271
|
+
</style>
|
|
2272
|
+
</head>
|
|
2273
|
+
<body>
|
|
2274
|
+
<div class="container">
|
|
2275
|
+
<h1>Authorization Failed</h1>
|
|
2276
|
+
<p>An error occurred during authorization.</p>
|
|
2277
|
+
<div class="error">${error}</div>
|
|
2278
|
+
</div>
|
|
2279
|
+
</body>
|
|
2280
|
+
</html>`;
|
|
2281
|
+
function ensureCredentialsDir() {
|
|
2282
|
+
if (!fs10__default.default.existsSync(AMA_DIR)) {
|
|
2283
|
+
fs10__default.default.mkdirSync(AMA_DIR, { recursive: true });
|
|
2284
|
+
}
|
|
2285
|
+
}
|
|
2286
|
+
function saveCredentials(credentials) {
|
|
2287
|
+
ensureCredentialsDir();
|
|
2288
|
+
fs10__default.default.writeFileSync(CREDENTIALS_PATH2, JSON.stringify(credentials, null, 2), "utf8");
|
|
2289
|
+
}
|
|
2290
|
+
function readCredentials() {
|
|
2291
|
+
if (!fs10__default.default.existsSync(CREDENTIALS_PATH2)) {
|
|
2292
|
+
return null;
|
|
2293
|
+
}
|
|
2294
|
+
const raw = fs10__default.default.readFileSync(CREDENTIALS_PATH2, "utf8");
|
|
2295
|
+
const parsed = JSON.parse(raw);
|
|
2296
|
+
if (typeof parsed.accessToken !== "string" || typeof parsed.refreshToken !== "string" || typeof parsed.accountId !== "string" || typeof parsed.expiresAt !== "number") {
|
|
2297
|
+
return null;
|
|
2298
|
+
}
|
|
2299
|
+
return parsed;
|
|
2300
|
+
}
|
|
2301
|
+
function generateRandomString(length) {
|
|
2302
|
+
const chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-._~";
|
|
2303
|
+
const bytes = crypto.getRandomValues(new Uint8Array(length));
|
|
2304
|
+
return Array.from(bytes).map((b) => chars[b % chars.length]).join("");
|
|
2305
|
+
}
|
|
2306
|
+
function base64UrlEncode(buffer) {
|
|
2307
|
+
const bytes = new Uint8Array(buffer);
|
|
2308
|
+
const binary = String.fromCharCode(...bytes);
|
|
2309
|
+
return btoa(binary).replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
|
|
2310
|
+
}
|
|
2311
|
+
async function generatePKCE() {
|
|
2312
|
+
const verifier = generateRandomString(43);
|
|
2313
|
+
const encoder = new TextEncoder();
|
|
2314
|
+
const data = encoder.encode(verifier);
|
|
2315
|
+
const hash = await crypto.subtle.digest("SHA-256", data);
|
|
2316
|
+
const challenge = base64UrlEncode(hash);
|
|
2317
|
+
return { verifier, challenge };
|
|
2318
|
+
}
|
|
2319
|
+
function generateState() {
|
|
2320
|
+
return base64UrlEncode(crypto.getRandomValues(new Uint8Array(32)).buffer);
|
|
2321
|
+
}
|
|
2322
|
+
function parseJwtClaims(token) {
|
|
2323
|
+
const parts = token.split(".");
|
|
2324
|
+
if (parts.length !== 3) {
|
|
2325
|
+
return void 0;
|
|
2326
|
+
}
|
|
2327
|
+
try {
|
|
2328
|
+
return JSON.parse(Buffer.from(parts[1], "base64url").toString("utf8"));
|
|
2329
|
+
} catch {
|
|
2330
|
+
return void 0;
|
|
2331
|
+
}
|
|
2332
|
+
}
|
|
2333
|
+
function extractAccountIdFromClaims(claims) {
|
|
2334
|
+
return claims.chatgpt_account_id || claims["https://api.openai.com/auth"]?.chatgpt_account_id || claims.organizations?.[0]?.id;
|
|
2335
|
+
}
|
|
2336
|
+
function extractAccountId(tokens) {
|
|
2337
|
+
if (tokens.id_token) {
|
|
2338
|
+
const claims = parseJwtClaims(tokens.id_token);
|
|
2339
|
+
const accountId = claims && extractAccountIdFromClaims(claims);
|
|
2340
|
+
if (accountId) {
|
|
2341
|
+
return accountId;
|
|
2342
|
+
}
|
|
2343
|
+
}
|
|
2344
|
+
const accessClaims = parseJwtClaims(tokens.access_token);
|
|
2345
|
+
return accessClaims ? extractAccountIdFromClaims(accessClaims) : void 0;
|
|
2346
|
+
}
|
|
2347
|
+
function buildAuthorizeUrl(redirectUri, pkce, state) {
|
|
2348
|
+
const params = new URLSearchParams({
|
|
2349
|
+
response_type: "code",
|
|
2350
|
+
client_id: CLIENT_ID2,
|
|
2351
|
+
redirect_uri: redirectUri,
|
|
2352
|
+
scope: "openid profile email offline_access",
|
|
2353
|
+
code_challenge: pkce.challenge,
|
|
2354
|
+
code_challenge_method: "S256",
|
|
2355
|
+
id_token_add_organizations: "true",
|
|
2356
|
+
codex_cli_simplified_flow: "true",
|
|
2357
|
+
state,
|
|
2358
|
+
originator: "ama"
|
|
2359
|
+
});
|
|
2360
|
+
return `${ISSUER}/oauth/authorize?${params.toString()}`;
|
|
2361
|
+
}
|
|
2362
|
+
async function exchangeCodeForTokens(code, redirectUri, pkce) {
|
|
2363
|
+
const response = await fetch(`${ISSUER}/oauth/token`, {
|
|
2364
|
+
method: "POST",
|
|
2365
|
+
headers: {
|
|
2366
|
+
"Content-Type": "application/x-www-form-urlencoded"
|
|
2367
|
+
},
|
|
2368
|
+
body: new URLSearchParams({
|
|
2369
|
+
grant_type: "authorization_code",
|
|
2370
|
+
code,
|
|
2371
|
+
redirect_uri: redirectUri,
|
|
2372
|
+
client_id: CLIENT_ID2,
|
|
2373
|
+
code_verifier: pkce.verifier
|
|
2374
|
+
}).toString()
|
|
2375
|
+
});
|
|
2376
|
+
if (!response.ok) {
|
|
2377
|
+
throw new Error(`Token exchange failed: ${response.status}`);
|
|
2378
|
+
}
|
|
2379
|
+
return response.json();
|
|
2380
|
+
}
|
|
2381
|
+
async function refreshAccessToken(refreshToken) {
|
|
2382
|
+
const response = await fetch(`${ISSUER}/oauth/token`, {
|
|
2383
|
+
method: "POST",
|
|
2384
|
+
headers: {
|
|
2385
|
+
"Content-Type": "application/x-www-form-urlencoded"
|
|
2386
|
+
},
|
|
2387
|
+
body: new URLSearchParams({
|
|
2388
|
+
grant_type: "refresh_token",
|
|
2389
|
+
refresh_token: refreshToken,
|
|
2390
|
+
client_id: CLIENT_ID2
|
|
2391
|
+
}).toString()
|
|
2392
|
+
});
|
|
2393
|
+
if (!response.ok) {
|
|
2394
|
+
throw new Error(`Token refresh failed: ${response.status}`);
|
|
2395
|
+
}
|
|
2396
|
+
return response.json();
|
|
2397
|
+
}
|
|
2398
|
+
async function startOAuthServer() {
|
|
2399
|
+
if (oauthServer) {
|
|
2400
|
+
return { redirectUri: `http://localhost:${OAUTH_PORT}${CALLBACK_PATH}` };
|
|
2401
|
+
}
|
|
2402
|
+
oauthServer = Bun.serve({
|
|
2403
|
+
port: OAUTH_PORT,
|
|
2404
|
+
fetch(request) {
|
|
2405
|
+
const url = new URL(request.url);
|
|
2406
|
+
if (url.pathname !== CALLBACK_PATH) {
|
|
2407
|
+
return new Response("Not found", { status: 404 });
|
|
2408
|
+
}
|
|
2409
|
+
const code = url.searchParams.get("code");
|
|
2410
|
+
const state = url.searchParams.get("state");
|
|
2411
|
+
const error = url.searchParams.get("error");
|
|
2412
|
+
const errorDescription = url.searchParams.get("error_description");
|
|
2413
|
+
if (error) {
|
|
2414
|
+
const message = errorDescription || error;
|
|
2415
|
+
pendingOAuth?.reject(new Error(message));
|
|
2416
|
+
pendingOAuth = void 0;
|
|
2417
|
+
return new Response(HTML_ERROR(message), {
|
|
2418
|
+
headers: { "Content-Type": "text/html" }
|
|
2419
|
+
});
|
|
2420
|
+
}
|
|
2421
|
+
if (!code) {
|
|
2422
|
+
const message = "Missing authorization code";
|
|
2423
|
+
pendingOAuth?.reject(new Error(message));
|
|
2424
|
+
pendingOAuth = void 0;
|
|
2425
|
+
return new Response(HTML_ERROR(message), {
|
|
2426
|
+
status: 400,
|
|
2427
|
+
headers: { "Content-Type": "text/html" }
|
|
2428
|
+
});
|
|
2429
|
+
}
|
|
2430
|
+
if (!pendingOAuth || state !== pendingOAuth.state) {
|
|
2431
|
+
const message = "Invalid state - potential CSRF attack";
|
|
2432
|
+
pendingOAuth?.reject(new Error(message));
|
|
2433
|
+
pendingOAuth = void 0;
|
|
2434
|
+
return new Response(HTML_ERROR(message), {
|
|
2435
|
+
status: 400,
|
|
2436
|
+
headers: { "Content-Type": "text/html" }
|
|
2437
|
+
});
|
|
2438
|
+
}
|
|
2439
|
+
const current = pendingOAuth;
|
|
2440
|
+
pendingOAuth = void 0;
|
|
2441
|
+
exchangeCodeForTokens(code, `http://localhost:${OAUTH_PORT}${CALLBACK_PATH}`, current.pkce).then((tokens) => current.resolve(tokens)).catch((err) => current.reject(err));
|
|
2442
|
+
return new Response(HTML_SUCCESS, {
|
|
2443
|
+
headers: { "Content-Type": "text/html" }
|
|
2444
|
+
});
|
|
2445
|
+
}
|
|
2446
|
+
});
|
|
2447
|
+
return { redirectUri: `http://localhost:${OAUTH_PORT}${CALLBACK_PATH}` };
|
|
2448
|
+
}
|
|
2449
|
+
function stopOAuthServer() {
|
|
2450
|
+
if (oauthServer) {
|
|
2451
|
+
oauthServer.stop();
|
|
2452
|
+
oauthServer = void 0;
|
|
2453
|
+
}
|
|
2454
|
+
}
|
|
2455
|
+
function waitForOAuthCallback(pkce, state) {
|
|
2456
|
+
if (pendingOAuth) {
|
|
2457
|
+
throw new Error("Codex authorization is already in progress");
|
|
2458
|
+
}
|
|
2459
|
+
return new Promise((resolve, reject) => {
|
|
2460
|
+
const timeout = setTimeout(() => {
|
|
2461
|
+
if (pendingOAuth) {
|
|
2462
|
+
pendingOAuth = void 0;
|
|
2463
|
+
reject(new Error("OAuth callback timeout - authorization took too long"));
|
|
2464
|
+
}
|
|
2465
|
+
}, OAUTH_TIMEOUT_MS);
|
|
2466
|
+
pendingOAuth = {
|
|
2467
|
+
pkce,
|
|
2468
|
+
state,
|
|
2469
|
+
resolve: (tokens) => {
|
|
2470
|
+
clearTimeout(timeout);
|
|
2471
|
+
resolve(tokens);
|
|
2472
|
+
},
|
|
2473
|
+
reject: (error) => {
|
|
2474
|
+
clearTimeout(timeout);
|
|
2475
|
+
reject(error);
|
|
2476
|
+
}
|
|
2477
|
+
};
|
|
2478
|
+
});
|
|
2479
|
+
}
|
|
2480
|
+
function maybeOpenBrowser(url) {
|
|
2481
|
+
try {
|
|
2482
|
+
if (process.platform === "darwin") {
|
|
2483
|
+
const child2 = child_process.spawn("open", [url], { detached: true, stdio: "ignore" });
|
|
2484
|
+
child2.unref();
|
|
2485
|
+
return;
|
|
2486
|
+
}
|
|
2487
|
+
if (process.platform === "win32") {
|
|
2488
|
+
const child2 = child_process.spawn("cmd", ["/c", "start", "", url], {
|
|
2489
|
+
detached: true,
|
|
2490
|
+
stdio: "ignore"
|
|
2491
|
+
});
|
|
2492
|
+
child2.unref();
|
|
2493
|
+
return;
|
|
2494
|
+
}
|
|
2495
|
+
const child = child_process.spawn("xdg-open", [url], { detached: true, stdio: "ignore" });
|
|
2496
|
+
child.unref();
|
|
2497
|
+
} catch {
|
|
2498
|
+
}
|
|
2499
|
+
}
|
|
2500
|
+
async function startCodexOAuth() {
|
|
2501
|
+
if (pendingOAuth) {
|
|
2502
|
+
throw new Error("Codex authorization is already in progress");
|
|
2503
|
+
}
|
|
2504
|
+
const { redirectUri } = await startOAuthServer();
|
|
2505
|
+
const pkce = await generatePKCE();
|
|
2506
|
+
const state = generateState();
|
|
2507
|
+
const authUrl = buildAuthorizeUrl(redirectUri, pkce, state);
|
|
2508
|
+
maybeOpenBrowser(authUrl);
|
|
2509
|
+
return {
|
|
2510
|
+
authUrl,
|
|
2511
|
+
waitForCallback: async () => {
|
|
2512
|
+
try {
|
|
2513
|
+
const tokens = await waitForOAuthCallback(pkce, state);
|
|
2514
|
+
const accountId = extractAccountId(tokens);
|
|
2515
|
+
if (!accountId) {
|
|
2516
|
+
throw new Error("Could not determine ChatGPT account ID from OAuth token");
|
|
2517
|
+
}
|
|
2518
|
+
const credentials = {
|
|
2519
|
+
accessToken: tokens.access_token,
|
|
2520
|
+
refreshToken: tokens.refresh_token,
|
|
2521
|
+
accountId,
|
|
2522
|
+
expiresAt: Date.now() + (tokens.expires_in ?? 3600) * 1e3
|
|
2523
|
+
};
|
|
2524
|
+
saveCredentials(credentials);
|
|
2525
|
+
return credentials;
|
|
2526
|
+
} finally {
|
|
2527
|
+
stopOAuthServer();
|
|
2528
|
+
}
|
|
2529
|
+
}
|
|
2530
|
+
};
|
|
2531
|
+
}
|
|
2532
|
+
async function getCodexTokens() {
|
|
2533
|
+
const credentials = readCredentials();
|
|
2534
|
+
if (!credentials) {
|
|
2535
|
+
throw new Error("Codex is not authenticated");
|
|
2536
|
+
}
|
|
2537
|
+
const needsRefresh = credentials.expiresAt <= Date.now() + REFRESH_BUFFER_MS;
|
|
2538
|
+
if (!needsRefresh) {
|
|
2539
|
+
return { accessToken: credentials.accessToken, accountId: credentials.accountId };
|
|
2540
|
+
}
|
|
2541
|
+
const refreshed = await refreshAccessToken(credentials.refreshToken);
|
|
2542
|
+
const nextAccountId = extractAccountId(refreshed) || credentials.accountId;
|
|
2543
|
+
const nextCredentials = {
|
|
2544
|
+
accessToken: refreshed.access_token,
|
|
2545
|
+
refreshToken: refreshed.refresh_token || credentials.refreshToken,
|
|
2546
|
+
accountId: nextAccountId,
|
|
2547
|
+
expiresAt: Date.now() + (refreshed.expires_in ?? 3600) * 1e3
|
|
2548
|
+
};
|
|
2549
|
+
saveCredentials(nextCredentials);
|
|
2550
|
+
return { accessToken: nextCredentials.accessToken, accountId: nextCredentials.accountId };
|
|
2551
|
+
}
|
|
2552
|
+
async function getCodexStatus() {
|
|
2553
|
+
const credentials = readCredentials();
|
|
2554
|
+
if (!credentials) {
|
|
2555
|
+
return { authenticated: false };
|
|
2556
|
+
}
|
|
2557
|
+
if (credentials.expiresAt > Date.now() + REFRESH_BUFFER_MS) {
|
|
2558
|
+
return { authenticated: true };
|
|
2559
|
+
}
|
|
2560
|
+
try {
|
|
2561
|
+
await getCodexTokens();
|
|
2562
|
+
return { authenticated: true };
|
|
2563
|
+
} catch {
|
|
2564
|
+
return { authenticated: false };
|
|
2565
|
+
}
|
|
2566
|
+
}
|
|
2567
|
+
async function codexLogout() {
|
|
2568
|
+
pendingOAuth = void 0;
|
|
2569
|
+
stopOAuthServer();
|
|
2570
|
+
if (fs10__default.default.existsSync(CREDENTIALS_PATH2)) {
|
|
2571
|
+
fs10__default.default.unlinkSync(CREDENTIALS_PATH2);
|
|
2572
|
+
}
|
|
2573
|
+
}
|
|
2184
2574
|
|
|
2185
2575
|
// src/lib/rpc-handlers.ts
|
|
2186
2576
|
var rpcHandlers = {
|
|
@@ -2329,6 +2719,23 @@ var rpcHandlers = {
|
|
|
2329
2719
|
}
|
|
2330
2720
|
const diff = await Snapshot.diff(projectId, hash);
|
|
2331
2721
|
return { success: true, diff };
|
|
2722
|
+
},
|
|
2723
|
+
"daemon:codex_start_auth": async () => {
|
|
2724
|
+
const { authUrl, waitForCallback } = await startCodexOAuth();
|
|
2725
|
+
void waitForCallback().catch((error) => {
|
|
2726
|
+
console.error("[codex] OAuth callback failed:", error);
|
|
2727
|
+
});
|
|
2728
|
+
return { authUrl };
|
|
2729
|
+
},
|
|
2730
|
+
"daemon:codex_get_tokens": async () => {
|
|
2731
|
+
return getCodexTokens();
|
|
2732
|
+
},
|
|
2733
|
+
"daemon:codex_status": async () => {
|
|
2734
|
+
return getCodexStatus();
|
|
2735
|
+
},
|
|
2736
|
+
"daemon:codex_logout": async () => {
|
|
2737
|
+
await codexLogout();
|
|
2738
|
+
return { success: true };
|
|
2332
2739
|
}
|
|
2333
2740
|
};
|
|
2334
2741
|
var INITIAL_RECONNECT_DELAY = 1e3;
|
|
@@ -2825,20 +3232,20 @@ function getCodeServerBin() {
|
|
|
2825
3232
|
}
|
|
2826
3233
|
function isCodeServerInstalled() {
|
|
2827
3234
|
const binPath = getCodeServerBin();
|
|
2828
|
-
return
|
|
3235
|
+
return fs10__default.default.existsSync(binPath);
|
|
2829
3236
|
}
|
|
2830
3237
|
async function installCodeServer() {
|
|
2831
3238
|
const { ext } = getPlatformInfo();
|
|
2832
3239
|
const downloadUrl = getDownloadUrl();
|
|
2833
3240
|
const tarballPath = path10__default.default.join(AMA_DIR, `code-server.${ext}`);
|
|
2834
|
-
if (!
|
|
2835
|
-
|
|
3241
|
+
if (!fs10__default.default.existsSync(AMA_DIR)) {
|
|
3242
|
+
fs10__default.default.mkdirSync(AMA_DIR, { recursive: true });
|
|
2836
3243
|
}
|
|
2837
|
-
if (!
|
|
2838
|
-
|
|
3244
|
+
if (!fs10__default.default.existsSync(CODE_DIR)) {
|
|
3245
|
+
fs10__default.default.mkdirSync(CODE_DIR, { recursive: true });
|
|
2839
3246
|
}
|
|
2840
|
-
if (!
|
|
2841
|
-
|
|
3247
|
+
if (!fs10__default.default.existsSync(STORAGE_DIR)) {
|
|
3248
|
+
fs10__default.default.mkdirSync(STORAGE_DIR, { recursive: true });
|
|
2842
3249
|
}
|
|
2843
3250
|
console.log(pc5__default.default.cyan(`downloading code-server v${CODE_SERVER_VERSION}...`));
|
|
2844
3251
|
console.log(pc5__default.default.gray(downloadUrl));
|
|
@@ -2847,13 +3254,13 @@ async function installCodeServer() {
|
|
|
2847
3254
|
throw new Error(`Failed to download code-server: ${response.statusText}`);
|
|
2848
3255
|
}
|
|
2849
3256
|
const buffer = await response.arrayBuffer();
|
|
2850
|
-
await
|
|
3257
|
+
await fs10__default.default.promises.writeFile(tarballPath, Buffer.from(buffer));
|
|
2851
3258
|
console.log(pc5__default.default.cyan("Extracting code-server..."));
|
|
2852
3259
|
await execAsync2(`tar -xzf ${tarballPath} -C ${CODE_DIR}`);
|
|
2853
|
-
await
|
|
3260
|
+
await fs10__default.default.promises.unlink(tarballPath);
|
|
2854
3261
|
const binPath = getCodeServerBin();
|
|
2855
|
-
if (
|
|
2856
|
-
await
|
|
3262
|
+
if (fs10__default.default.existsSync(binPath)) {
|
|
3263
|
+
await fs10__default.default.promises.chmod(binPath, 493);
|
|
2857
3264
|
}
|
|
2858
3265
|
console.log(pc5__default.default.green("code-server installed successfully"));
|
|
2859
3266
|
}
|
|
@@ -2878,8 +3285,8 @@ async function killExistingCodeServer() {
|
|
|
2878
3285
|
async function setupDefaultSettings() {
|
|
2879
3286
|
const userDir = path10__default.default.join(STORAGE_DIR, "User");
|
|
2880
3287
|
const settingsPath = path10__default.default.join(userDir, "settings.json");
|
|
2881
|
-
if (!
|
|
2882
|
-
|
|
3288
|
+
if (!fs10__default.default.existsSync(userDir)) {
|
|
3289
|
+
fs10__default.default.mkdirSync(userDir, { recursive: true });
|
|
2883
3290
|
}
|
|
2884
3291
|
const defaultSettings = {
|
|
2885
3292
|
// Disable signature verification for Open VSX extensions
|
|
@@ -2897,9 +3304,9 @@ async function setupDefaultSettings() {
|
|
|
2897
3304
|
"workbench.activityBar.location": "top"
|
|
2898
3305
|
};
|
|
2899
3306
|
let existingSettings = {};
|
|
2900
|
-
if (
|
|
3307
|
+
if (fs10__default.default.existsSync(settingsPath)) {
|
|
2901
3308
|
try {
|
|
2902
|
-
const content = await
|
|
3309
|
+
const content = await fs10__default.default.promises.readFile(settingsPath, "utf-8");
|
|
2903
3310
|
existingSettings = JSON.parse(content);
|
|
2904
3311
|
} catch {
|
|
2905
3312
|
}
|
|
@@ -2907,7 +3314,7 @@ async function setupDefaultSettings() {
|
|
|
2907
3314
|
const mergedSettings = { ...defaultSettings, ...existingSettings };
|
|
2908
3315
|
mergedSettings["workbench.colorTheme"] = "Min Dark";
|
|
2909
3316
|
mergedSettings["extensions.verifySignature"] = false;
|
|
2910
|
-
await
|
|
3317
|
+
await fs10__default.default.promises.writeFile(settingsPath, JSON.stringify(mergedSettings, null, 2));
|
|
2911
3318
|
console.log(pc5__default.default.green("ama code-server settings configured"));
|
|
2912
3319
|
}
|
|
2913
3320
|
async function installExtensions() {
|
|
@@ -2928,7 +3335,7 @@ async function installExtensions() {
|
|
|
2928
3335
|
async function startCodeServer(cwd) {
|
|
2929
3336
|
const binPath = getCodeServerBin();
|
|
2930
3337
|
const workDir = cwd || process.cwd();
|
|
2931
|
-
if (!
|
|
3338
|
+
if (!fs10__default.default.existsSync(binPath)) {
|
|
2932
3339
|
throw new Error("ama code-server is not installed. Run installCodeServer() first.");
|
|
2933
3340
|
}
|
|
2934
3341
|
await killExistingCodeServer();
|
|
@@ -2936,12 +3343,12 @@ async function startCodeServer(cwd) {
|
|
|
2936
3343
|
await installExtensions();
|
|
2937
3344
|
const workspaceStoragePath = path10__default.default.join(STORAGE_DIR, "User", "workspaceStorage");
|
|
2938
3345
|
try {
|
|
2939
|
-
if (
|
|
2940
|
-
await
|
|
3346
|
+
if (fs10__default.default.existsSync(workspaceStoragePath)) {
|
|
3347
|
+
await fs10__default.default.promises.rm(workspaceStoragePath, { recursive: true, force: true });
|
|
2941
3348
|
}
|
|
2942
3349
|
const stateDbPath = path10__default.default.join(STORAGE_DIR, "User", "globalStorage", "state.vscdb");
|
|
2943
|
-
if (
|
|
2944
|
-
await
|
|
3350
|
+
if (fs10__default.default.existsSync(stateDbPath)) {
|
|
3351
|
+
await fs10__default.default.promises.unlink(stateDbPath);
|
|
2945
3352
|
}
|
|
2946
3353
|
} catch {
|
|
2947
3354
|
}
|
|
@@ -2972,11 +3379,11 @@ var __dirname$1 = path10.dirname(__filename$1);
|
|
|
2972
3379
|
var DAEMON_PID_FILE = path10__default.default.join(AMA_DIR, "daemon.pid");
|
|
2973
3380
|
var DAEMON_LOG_FILE = path10__default.default.join(AMA_DIR, "daemon.log");
|
|
2974
3381
|
function isDaemonRunning() {
|
|
2975
|
-
if (!
|
|
3382
|
+
if (!fs10__default.default.existsSync(DAEMON_PID_FILE)) {
|
|
2976
3383
|
return false;
|
|
2977
3384
|
}
|
|
2978
3385
|
try {
|
|
2979
|
-
const pid = Number(
|
|
3386
|
+
const pid = Number(fs10__default.default.readFileSync(DAEMON_PID_FILE, "utf8"));
|
|
2980
3387
|
process.kill(pid, 0);
|
|
2981
3388
|
return true;
|
|
2982
3389
|
} catch {
|
|
@@ -2984,30 +3391,30 @@ function isDaemonRunning() {
|
|
|
2984
3391
|
}
|
|
2985
3392
|
}
|
|
2986
3393
|
function stopDaemon() {
|
|
2987
|
-
if (!
|
|
3394
|
+
if (!fs10__default.default.existsSync(DAEMON_PID_FILE)) {
|
|
2988
3395
|
return false;
|
|
2989
3396
|
}
|
|
2990
3397
|
try {
|
|
2991
|
-
const pid = Number(
|
|
3398
|
+
const pid = Number(fs10__default.default.readFileSync(DAEMON_PID_FILE, "utf8"));
|
|
2992
3399
|
process.kill(pid, "SIGTERM");
|
|
2993
|
-
|
|
3400
|
+
fs10__default.default.unlinkSync(DAEMON_PID_FILE);
|
|
2994
3401
|
return true;
|
|
2995
3402
|
} catch (error) {
|
|
2996
3403
|
return false;
|
|
2997
3404
|
}
|
|
2998
3405
|
}
|
|
2999
3406
|
function startDaemon() {
|
|
3000
|
-
if (!
|
|
3001
|
-
|
|
3407
|
+
if (!fs10__default.default.existsSync(AMA_DIR)) {
|
|
3408
|
+
fs10__default.default.mkdirSync(AMA_DIR, { recursive: true });
|
|
3002
3409
|
}
|
|
3003
3410
|
if (isDaemonRunning()) {
|
|
3004
3411
|
stopDaemon();
|
|
3005
3412
|
}
|
|
3006
3413
|
const daemonScript = path10__default.default.join(__dirname$1, "lib", "daemon-entry.js");
|
|
3007
|
-
if (!
|
|
3414
|
+
if (!fs10__default.default.existsSync(daemonScript)) {
|
|
3008
3415
|
throw new Error(`Daemon entry script not found at: ${daemonScript}. Please rebuild the project.`);
|
|
3009
3416
|
}
|
|
3010
|
-
const logFd =
|
|
3417
|
+
const logFd = fs10__default.default.openSync(DAEMON_LOG_FILE, "a");
|
|
3011
3418
|
const daemon = child_process.spawn(process.execPath, [daemonScript], {
|
|
3012
3419
|
detached: true,
|
|
3013
3420
|
stdio: ["ignore", logFd, logFd],
|
|
@@ -3015,20 +3422,20 @@ function startDaemon() {
|
|
|
3015
3422
|
cwd: process.cwd()
|
|
3016
3423
|
});
|
|
3017
3424
|
daemon.unref();
|
|
3018
|
-
|
|
3019
|
-
|
|
3425
|
+
fs10__default.default.writeFileSync(DAEMON_PID_FILE, String(daemon.pid));
|
|
3426
|
+
fs10__default.default.closeSync(logFd);
|
|
3020
3427
|
}
|
|
3021
3428
|
function getDaemonPid() {
|
|
3022
|
-
if (!
|
|
3429
|
+
if (!fs10__default.default.existsSync(DAEMON_PID_FILE)) {
|
|
3023
3430
|
return null;
|
|
3024
3431
|
}
|
|
3025
3432
|
try {
|
|
3026
|
-
return Number(
|
|
3433
|
+
return Number(fs10__default.default.readFileSync(DAEMON_PID_FILE, "utf8"));
|
|
3027
3434
|
} catch {
|
|
3028
3435
|
return null;
|
|
3029
3436
|
}
|
|
3030
3437
|
}
|
|
3031
|
-
var VERSION = "0.0.
|
|
3438
|
+
var VERSION = "0.0.18";
|
|
3032
3439
|
var PROJECT_DIR = process.cwd();
|
|
3033
3440
|
var LOGO = `
|
|
3034
3441
|
__ _ _ __ ___ __ _
|
|
@@ -3108,6 +3515,9 @@ if (args[0] === "--help" || args[0] === "-h") {
|
|
|
3108
3515
|
console.log("");
|
|
3109
3516
|
console.log(pc5__default.default.cyan(" commands"));
|
|
3110
3517
|
console.log(pc5__default.default.gray(" login authenticate with amai"));
|
|
3518
|
+
console.log(pc5__default.default.gray(" codex connect ChatGPT subscription for Codex"));
|
|
3519
|
+
console.log(pc5__default.default.gray(" codex status check Codex auth status"));
|
|
3520
|
+
console.log(pc5__default.default.gray(" codex logout remove Codex credentials"));
|
|
3111
3521
|
console.log(pc5__default.default.gray(" logout remove credentials"));
|
|
3112
3522
|
console.log(pc5__default.default.gray(" start start background daemon"));
|
|
3113
3523
|
console.log(pc5__default.default.gray(" stop stop background daemon"));
|
|
@@ -3144,6 +3554,33 @@ if (args[0] === "update") {
|
|
|
3144
3554
|
}
|
|
3145
3555
|
process.exit(0);
|
|
3146
3556
|
})();
|
|
3557
|
+
} else if (args[0] === "codex") {
|
|
3558
|
+
(async () => {
|
|
3559
|
+
try {
|
|
3560
|
+
const subCommand = args[1];
|
|
3561
|
+
if (subCommand === "status") {
|
|
3562
|
+
const status = await getCodexStatus();
|
|
3563
|
+
console.log(pc5__default.default.gray(`codex auth: ${status.authenticated ? "connected" : "not connected"}`));
|
|
3564
|
+
process.exit(0);
|
|
3565
|
+
}
|
|
3566
|
+
if (subCommand === "logout") {
|
|
3567
|
+
await codexLogout();
|
|
3568
|
+
console.log(pc5__default.default.cyan("codex credentials removed"));
|
|
3569
|
+
process.exit(0);
|
|
3570
|
+
}
|
|
3571
|
+
console.log(pc5__default.default.gray("starting codex auth..."));
|
|
3572
|
+
const { authUrl, waitForCallback } = await startCodexOAuth();
|
|
3573
|
+
console.log("");
|
|
3574
|
+
console.log(pc5__default.default.cyan(`open: ${authUrl}`));
|
|
3575
|
+
console.log(pc5__default.default.gray("complete authorization in your browser..."));
|
|
3576
|
+
const result = await waitForCallback();
|
|
3577
|
+
console.log(pc5__default.default.cyan(`codex connected (account: ${result.accountId})`));
|
|
3578
|
+
process.exit(0);
|
|
3579
|
+
} catch (error) {
|
|
3580
|
+
console.error(pc5__default.default.red(error.message || "codex auth failed"));
|
|
3581
|
+
process.exit(1);
|
|
3582
|
+
}
|
|
3583
|
+
})();
|
|
3147
3584
|
} else if (args[0] === "start") {
|
|
3148
3585
|
(async () => {
|
|
3149
3586
|
if (isDaemonRunning()) {
|
|
@@ -3195,11 +3632,11 @@ if (args[0] === "update") {
|
|
|
3195
3632
|
process.exit(1);
|
|
3196
3633
|
}
|
|
3197
3634
|
const resolvedPath = path10__default.default.resolve(projectPath);
|
|
3198
|
-
if (!
|
|
3635
|
+
if (!fs10__default.default.existsSync(resolvedPath)) {
|
|
3199
3636
|
console.error(pc5__default.default.red(`path does not exist: ${resolvedPath}`));
|
|
3200
3637
|
process.exit(1);
|
|
3201
3638
|
}
|
|
3202
|
-
if (!
|
|
3639
|
+
if (!fs10__default.default.statSync(resolvedPath).isDirectory()) {
|
|
3203
3640
|
console.error(pc5__default.default.red(`path is not a directory: ${resolvedPath}`));
|
|
3204
3641
|
process.exit(1);
|
|
3205
3642
|
}
|