@overaihq/cli 0.6.0 → 0.8.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.
|
@@ -362,6 +362,14 @@ var consoleLogsPayloadSchema = external_exports.object({
|
|
|
362
362
|
var runtimeErrorPayloadSchema = external_exports.object({
|
|
363
363
|
error: external_exports.string().nullable()
|
|
364
364
|
});
|
|
365
|
+
var pageInteractionPayloadSchema = external_exports.object({
|
|
366
|
+
clicks: external_exports.number().int().min(0),
|
|
367
|
+
keypresses: external_exports.number().int().min(0)
|
|
368
|
+
});
|
|
369
|
+
var pageErrorPayloadSchema = external_exports.object({
|
|
370
|
+
message: external_exports.string(),
|
|
371
|
+
stack: external_exports.string().optional()
|
|
372
|
+
});
|
|
365
373
|
|
|
366
374
|
// ../common/src/webPage.ts
|
|
367
375
|
var webPageLanguage = ["react"];
|
package/dist/index.js
CHANGED
|
@@ -5,7 +5,7 @@ import {
|
|
|
5
5
|
import {
|
|
6
6
|
itemFilterExpressionRootSchema,
|
|
7
7
|
webPageConfigSchema
|
|
8
|
-
} from "./chunk-
|
|
8
|
+
} from "./chunk-2F4ZHHFG.js";
|
|
9
9
|
import {
|
|
10
10
|
external_exports
|
|
11
11
|
} from "./chunk-6YTIPJTD.js";
|
|
@@ -26360,11 +26360,6 @@ var require_lib2 = __commonJS({
|
|
|
26360
26360
|
}
|
|
26361
26361
|
});
|
|
26362
26362
|
|
|
26363
|
-
// src/auth.ts
|
|
26364
|
-
import { randomBytes as randomBytes2 } from "crypto";
|
|
26365
|
-
import { createServer } from "http";
|
|
26366
|
-
import { hostname } from "os";
|
|
26367
|
-
|
|
26368
26363
|
// src/config.ts
|
|
26369
26364
|
import {
|
|
26370
26365
|
chmodSync,
|
|
@@ -26401,6 +26396,7 @@ var clearConfig = () => {
|
|
|
26401
26396
|
var trimSlash = (url) => url.replace(/\/+$/, "");
|
|
26402
26397
|
var DEFAULT_API_BASE_URL = "https://api.overai.com";
|
|
26403
26398
|
var apiBaseUrlOverride = process.env.OVERAI_API_URL != null ? trimSlash(process.env.OVERAI_API_URL) : void 0;
|
|
26399
|
+
var orgIdOverride = process.env.OVERAI_ORG_ID != null && process.env.OVERAI_ORG_ID !== "" ? process.env.OVERAI_ORG_ID : void 0;
|
|
26404
26400
|
var appBaseUrl = trimSlash(
|
|
26405
26401
|
process.env.OVERAI_APP_URL ?? "https://app.overai.com"
|
|
26406
26402
|
);
|
|
@@ -26449,6 +26445,21 @@ var orgScopeOverride = null;
|
|
|
26449
26445
|
var setOrgScope = (organizationId) => {
|
|
26450
26446
|
orgScopeOverride = organizationId;
|
|
26451
26447
|
};
|
|
26448
|
+
var resolveOrgId = (config) => orgIdOverride ?? orgScopeOverride ?? config.organizationId;
|
|
26449
|
+
var scopedOrgId = () => {
|
|
26450
|
+
const config = readConfig();
|
|
26451
|
+
return config == null ? null : resolveOrgId(config);
|
|
26452
|
+
};
|
|
26453
|
+
var announceOrgScope = () => {
|
|
26454
|
+
const config = readConfig();
|
|
26455
|
+
if (config == null) return;
|
|
26456
|
+
const targetOrgId = resolveOrgId(config);
|
|
26457
|
+
if (targetOrgId === config.organizationId) return;
|
|
26458
|
+
process.stderr.write(
|
|
26459
|
+
`Using org ${targetOrgId} (${orgIdOverride != null ? "OVERAI_ORG_ID" : ".overai/manifest.json"}); the active org is ${config.organizationId}.
|
|
26460
|
+
`
|
|
26461
|
+
);
|
|
26462
|
+
};
|
|
26452
26463
|
var inFlightExchange = null;
|
|
26453
26464
|
var processToken = null;
|
|
26454
26465
|
var getAccessToken = async () => {
|
|
@@ -26456,7 +26467,7 @@ var getAccessToken = async () => {
|
|
|
26456
26467
|
if (config == null) {
|
|
26457
26468
|
throw new Error("Not signed in. Run `overai signin`.");
|
|
26458
26469
|
}
|
|
26459
|
-
const targetOrgId =
|
|
26470
|
+
const targetOrgId = resolveOrgId(config);
|
|
26460
26471
|
const skewMs = 6e4;
|
|
26461
26472
|
if (targetOrgId === config.organizationId && config.accessToken != null && config.accessTokenExpiresAt != null && config.accessTokenExpiresAt - skewMs > Date.now()) {
|
|
26462
26473
|
return { token: config.accessToken, organizationId: config.organizationId };
|
|
@@ -26498,6 +26509,45 @@ var v2Fetch = async (path, init) => {
|
|
|
26498
26509
|
headers.set("Authorization", `Bearer ${auth.token}`);
|
|
26499
26510
|
return fetch(`${apiBaseUrl()}${path}`, { ...init, headers });
|
|
26500
26511
|
};
|
|
26512
|
+
var STATUS_TEXT = {
|
|
26513
|
+
400: "Bad Request",
|
|
26514
|
+
401: "Unauthorized",
|
|
26515
|
+
403: "Forbidden",
|
|
26516
|
+
404: "Not Found",
|
|
26517
|
+
409: "Conflict",
|
|
26518
|
+
413: "Payload Too Large",
|
|
26519
|
+
429: "Too Many Requests",
|
|
26520
|
+
500: "Internal Server Error",
|
|
26521
|
+
503: "Service Unavailable"
|
|
26522
|
+
};
|
|
26523
|
+
var v2Error = (label, res, rawBody) => {
|
|
26524
|
+
const structured = (() => {
|
|
26525
|
+
try {
|
|
26526
|
+
return JSON.parse(rawBody);
|
|
26527
|
+
} catch {
|
|
26528
|
+
return null;
|
|
26529
|
+
}
|
|
26530
|
+
})();
|
|
26531
|
+
const field = structured?.error ?? structured?.message;
|
|
26532
|
+
const claimed = (typeof field === "string" ? field : rawBody).trim().slice(0, 500);
|
|
26533
|
+
const reason = claimed.length === 0 || claimed === "Error" || claimed === "null" || claimed === "undefined" || claimed.toLowerCase() === STATUS_TEXT[res.status]?.toLowerCase() ? null : claimed;
|
|
26534
|
+
const orgHint = res.status === 404 || res.status === 403 ? `
|
|
26535
|
+
If it lives in another org, prefix the command with OVERAI_ORG_ID=<orgId> (\`overai org list\` shows them).` : "";
|
|
26536
|
+
if (reason != null) return new Error(`${reason}${orgHint}`);
|
|
26537
|
+
const path = (() => {
|
|
26538
|
+
try {
|
|
26539
|
+
return new URL(res.url).pathname;
|
|
26540
|
+
} catch {
|
|
26541
|
+
return "";
|
|
26542
|
+
}
|
|
26543
|
+
})();
|
|
26544
|
+
const org = scopedOrgId();
|
|
26545
|
+
return new Error(
|
|
26546
|
+
`${label}: HTTP ${String(res.status)}, no reason given by the server.${path === "" ? "" : `
|
|
26547
|
+
${path}`}${org == null ? "" : `
|
|
26548
|
+
Asked as org ${org}.`}${orgHint}`
|
|
26549
|
+
);
|
|
26550
|
+
};
|
|
26501
26551
|
var userTrpcMutation = async (procedure, input) => {
|
|
26502
26552
|
const res = await v2Fetch(`/v1/utils/trpc/${procedure}`, {
|
|
26503
26553
|
method: "POST",
|
|
@@ -26507,6 +26557,11 @@ var userTrpcMutation = async (procedure, input) => {
|
|
|
26507
26557
|
return trpcResult(res, procedure);
|
|
26508
26558
|
};
|
|
26509
26559
|
|
|
26560
|
+
// src/auth.ts
|
|
26561
|
+
import { randomBytes as randomBytes2 } from "crypto";
|
|
26562
|
+
import { createServer } from "http";
|
|
26563
|
+
import { hostname } from "os";
|
|
26564
|
+
|
|
26510
26565
|
// src/browser.ts
|
|
26511
26566
|
import { spawn } from "child_process";
|
|
26512
26567
|
import { platform } from "os";
|
|
@@ -26521,6 +26576,175 @@ var openBrowser = (url) => {
|
|
|
26521
26576
|
}
|
|
26522
26577
|
};
|
|
26523
26578
|
|
|
26579
|
+
// src/args.ts
|
|
26580
|
+
import { readFileSync as readFileSync2 } from "fs";
|
|
26581
|
+
var flagValue = (args, ...names) => {
|
|
26582
|
+
for (const name2 of names) {
|
|
26583
|
+
const i = args.indexOf(name2);
|
|
26584
|
+
if (i !== -1 && i + 1 < args.length) return args[i + 1];
|
|
26585
|
+
}
|
|
26586
|
+
return void 0;
|
|
26587
|
+
};
|
|
26588
|
+
var stdinClaimedBy = null;
|
|
26589
|
+
var readStdin = async (claimant = "stdin") => {
|
|
26590
|
+
if (stdinClaimedBy != null) {
|
|
26591
|
+
throw new Error(
|
|
26592
|
+
`Only one value can be read from stdin; ${stdinClaimedBy} already consumed it.`
|
|
26593
|
+
);
|
|
26594
|
+
}
|
|
26595
|
+
stdinClaimedBy = claimant;
|
|
26596
|
+
const chunks = [];
|
|
26597
|
+
for await (const chunk of process.stdin) {
|
|
26598
|
+
chunks.push(chunk);
|
|
26599
|
+
}
|
|
26600
|
+
return Buffer.concat(chunks).toString("utf8");
|
|
26601
|
+
};
|
|
26602
|
+
var readValue = async (value, label) => {
|
|
26603
|
+
if (value?.startsWith("@") !== true) return value;
|
|
26604
|
+
if (value.startsWith("@@")) return value.slice(1);
|
|
26605
|
+
const path = value.slice(1);
|
|
26606
|
+
if (path === "-") return (await readStdin(`${label} @-`)).trim();
|
|
26607
|
+
try {
|
|
26608
|
+
return readFileSync2(path, "utf8").trim();
|
|
26609
|
+
} catch {
|
|
26610
|
+
throw new Error(
|
|
26611
|
+
`${label}: could not read file "${path}". Write "@@" to send a literal value starting with "@".`
|
|
26612
|
+
);
|
|
26613
|
+
}
|
|
26614
|
+
};
|
|
26615
|
+
|
|
26616
|
+
// src/output.ts
|
|
26617
|
+
var resolveFormat = (explicit) => {
|
|
26618
|
+
if (explicit === "json" || explicit === "csv" || explicit === "table") {
|
|
26619
|
+
return explicit;
|
|
26620
|
+
}
|
|
26621
|
+
if (explicit != null) {
|
|
26622
|
+
throw new Error(
|
|
26623
|
+
`Unknown output format "${explicit}". Use json, table, or csv.`
|
|
26624
|
+
);
|
|
26625
|
+
}
|
|
26626
|
+
return process.stdout.isTTY ? "table" : "json";
|
|
26627
|
+
};
|
|
26628
|
+
var cell = (value) => {
|
|
26629
|
+
if (value == null) return "";
|
|
26630
|
+
if (typeof value === "string") return value;
|
|
26631
|
+
if (typeof value === "number" || typeof value === "boolean" || typeof value === "bigint") {
|
|
26632
|
+
return String(value);
|
|
26633
|
+
}
|
|
26634
|
+
return JSON.stringify(value);
|
|
26635
|
+
};
|
|
26636
|
+
var formatResult = (data, format2) => {
|
|
26637
|
+
if (format2 === "json" || !Array.isArray(data)) {
|
|
26638
|
+
return JSON.stringify(data, null, 2);
|
|
26639
|
+
}
|
|
26640
|
+
const records = data.map(
|
|
26641
|
+
(row) => row != null && typeof row === "object" ? row : { value: row }
|
|
26642
|
+
);
|
|
26643
|
+
if (records.length === 0) return "(no rows)";
|
|
26644
|
+
const columns = [...new Set(records.flatMap((r) => Object.keys(r)))];
|
|
26645
|
+
if (format2 === "csv") {
|
|
26646
|
+
const escape2 = (value) => {
|
|
26647
|
+
const text = cell(value);
|
|
26648
|
+
return /[",\n\r]/.test(text) ? `"${text.replace(/"/g, '""')}"` : text;
|
|
26649
|
+
};
|
|
26650
|
+
return [
|
|
26651
|
+
columns.join(","),
|
|
26652
|
+
...records.map((r) => columns.map((c) => escape2(r[c])).join(","))
|
|
26653
|
+
].join("\n");
|
|
26654
|
+
}
|
|
26655
|
+
const widths = columns.map(
|
|
26656
|
+
(c) => Math.max(c.length, ...records.map((r) => cell(r[c]).length))
|
|
26657
|
+
);
|
|
26658
|
+
const line = (cells) => cells.map((text, i) => text.padEnd(widths[i] ?? 0)).join(" ");
|
|
26659
|
+
return [
|
|
26660
|
+
line(columns),
|
|
26661
|
+
line(widths.map((w) => "-".repeat(w))),
|
|
26662
|
+
...records.map((r) => line(columns.map((c) => cell(r[c]))))
|
|
26663
|
+
].join("\n");
|
|
26664
|
+
};
|
|
26665
|
+
var printResult = (data, format2) => {
|
|
26666
|
+
process.stdout.write(`${formatResult(data, format2)}
|
|
26667
|
+
`);
|
|
26668
|
+
};
|
|
26669
|
+
|
|
26670
|
+
// src/commands/org.ts
|
|
26671
|
+
var USER_ORGS_QUERY = `
|
|
26672
|
+
query UserOrganizations($identityId: String!) {
|
|
26673
|
+
identityOrganizations(
|
|
26674
|
+
where: { identityId: { _eq: $identityId }, disabled: { _eq: false } }
|
|
26675
|
+
) {
|
|
26676
|
+
organization { id name }
|
|
26677
|
+
}
|
|
26678
|
+
}
|
|
26679
|
+
`;
|
|
26680
|
+
var fetchOrgNames = async () => {
|
|
26681
|
+
const orgs = await listOrgRows();
|
|
26682
|
+
return new Map(orgs.map((org) => [org.id, org.name ?? ""]));
|
|
26683
|
+
};
|
|
26684
|
+
var listOrgRows = async () => {
|
|
26685
|
+
const auth = await getAccessToken();
|
|
26686
|
+
const identityId = decodeJwtClaims(auth.token).user_id;
|
|
26687
|
+
if (identityId == null) {
|
|
26688
|
+
throw new Error("Could not read identity from the current session.");
|
|
26689
|
+
}
|
|
26690
|
+
const res = await v2Fetch("/v1/graphql", {
|
|
26691
|
+
method: "POST",
|
|
26692
|
+
headers: { "Content-Type": "application/json" },
|
|
26693
|
+
body: JSON.stringify({ query: USER_ORGS_QUERY, variables: { identityId } })
|
|
26694
|
+
});
|
|
26695
|
+
const body = await res.json().catch(() => null);
|
|
26696
|
+
if (body?.errors != null && body.errors.length > 0) {
|
|
26697
|
+
throw new Error(body.errors.map((e) => e.message).join("; "));
|
|
26698
|
+
}
|
|
26699
|
+
if (!res.ok || body == null) {
|
|
26700
|
+
throw new Error(`org list failed (${String(res.status)})`);
|
|
26701
|
+
}
|
|
26702
|
+
return (body.data?.identityOrganizations ?? []).map((edge) => edge.organization).filter((org) => org != null);
|
|
26703
|
+
};
|
|
26704
|
+
var listOrgs = async (args) => {
|
|
26705
|
+
const active = scopedOrgId();
|
|
26706
|
+
printResult(
|
|
26707
|
+
(await listOrgRows()).map((org) => ({
|
|
26708
|
+
id: org.id,
|
|
26709
|
+
name: org.name ?? "",
|
|
26710
|
+
active: org.id === active
|
|
26711
|
+
})),
|
|
26712
|
+
resolveFormat(flagValue(args, "-o", "--output"))
|
|
26713
|
+
);
|
|
26714
|
+
};
|
|
26715
|
+
var switchOrg = async (orgId) => {
|
|
26716
|
+
const config = readConfig();
|
|
26717
|
+
if (config == null) {
|
|
26718
|
+
process.stderr.write("Not signed in. Run `overai signin`.\n");
|
|
26719
|
+
process.exitCode = 1;
|
|
26720
|
+
return;
|
|
26721
|
+
}
|
|
26722
|
+
const result = await exchangeSessionToken(config.refreshToken, orgId);
|
|
26723
|
+
if (result.type === "redirect") {
|
|
26724
|
+
process.stdout.write(
|
|
26725
|
+
`This organization requires SSO. Complete sign-in in your browser, then run \`overai signin\`.
|
|
26726
|
+
${result.redirectUrl}
|
|
26727
|
+
`
|
|
26728
|
+
);
|
|
26729
|
+
openBrowser(result.redirectUrl);
|
|
26730
|
+
process.exitCode = 1;
|
|
26731
|
+
return;
|
|
26732
|
+
}
|
|
26733
|
+
writeConfig({
|
|
26734
|
+
...config,
|
|
26735
|
+
organizationId: orgId,
|
|
26736
|
+
email: decodeJwtClaims(result.token).email ?? config.email,
|
|
26737
|
+
accessToken: result.token,
|
|
26738
|
+
accessTokenExpiresAt: Date.now() + result.accessTokenValiditySeconds * 1e3,
|
|
26739
|
+
refreshToken: result.refreshToken
|
|
26740
|
+
});
|
|
26741
|
+
process.stdout.write(
|
|
26742
|
+
`Switched to org ${orgId}.
|
|
26743
|
+
This is machine-global \u2014 every shell and editor session on this machine now uses it. Prefix a command with OVERAI_ORG_ID=<orgId> to scope just one.
|
|
26744
|
+
`
|
|
26745
|
+
);
|
|
26746
|
+
};
|
|
26747
|
+
|
|
26524
26748
|
// src/pkce.ts
|
|
26525
26749
|
import { createHash, randomBytes } from "crypto";
|
|
26526
26750
|
var createPkcePair = () => {
|
|
@@ -26529,6 +26753,87 @@ var createPkcePair = () => {
|
|
|
26529
26753
|
return { verifier, challenge };
|
|
26530
26754
|
};
|
|
26531
26755
|
|
|
26756
|
+
// src/workspace/manifest.ts
|
|
26757
|
+
import { existsSync, mkdirSync as mkdirSync2, readFileSync as readFileSync3, writeFileSync as writeFileSync2 } from "fs";
|
|
26758
|
+
import { dirname, join as join2, resolve } from "path";
|
|
26759
|
+
var MANIFEST_DIR = ".overai";
|
|
26760
|
+
var MANIFEST_FILE = "manifest.json";
|
|
26761
|
+
var BASE_DIR = "base";
|
|
26762
|
+
var findWorkspaceRoot = (from = process.cwd()) => {
|
|
26763
|
+
let dir = resolve(from);
|
|
26764
|
+
for (; ; ) {
|
|
26765
|
+
if (existsSync(join2(dir, MANIFEST_DIR, MANIFEST_FILE))) return dir;
|
|
26766
|
+
const parent = dirname(dir);
|
|
26767
|
+
if (parent === dir) {
|
|
26768
|
+
throw new Error(
|
|
26769
|
+
"Not inside a cloned workspace (no .overai/manifest.json found). Run `overai clone <workspaceId>` first."
|
|
26770
|
+
);
|
|
26771
|
+
}
|
|
26772
|
+
dir = parent;
|
|
26773
|
+
}
|
|
26774
|
+
};
|
|
26775
|
+
var readManifest = (root) => JSON.parse(
|
|
26776
|
+
readFileSync3(join2(root, MANIFEST_DIR, MANIFEST_FILE), "utf8")
|
|
26777
|
+
);
|
|
26778
|
+
var openClone = () => {
|
|
26779
|
+
const root = findWorkspaceRoot();
|
|
26780
|
+
const manifest = readManifest(root);
|
|
26781
|
+
setOrgScope(manifest.organizationId);
|
|
26782
|
+
return { root, manifest };
|
|
26783
|
+
};
|
|
26784
|
+
var pinOrgFromClone = () => {
|
|
26785
|
+
try {
|
|
26786
|
+
setOrgScope(readManifest(findWorkspaceRoot()).organizationId);
|
|
26787
|
+
} catch {
|
|
26788
|
+
}
|
|
26789
|
+
};
|
|
26790
|
+
var writeManifest = (root, manifest) => {
|
|
26791
|
+
mkdirSync2(join2(root, MANIFEST_DIR), { recursive: true });
|
|
26792
|
+
writeFileSync2(
|
|
26793
|
+
join2(root, MANIFEST_DIR, MANIFEST_FILE),
|
|
26794
|
+
`${JSON.stringify(manifest, null, 2)}
|
|
26795
|
+
`
|
|
26796
|
+
);
|
|
26797
|
+
};
|
|
26798
|
+
var basePath = (root, relPath) => join2(root, MANIFEST_DIR, BASE_DIR, relPath);
|
|
26799
|
+
var writeSynced = (root, relPath, content) => {
|
|
26800
|
+
for (const abs2 of [join2(root, relPath), basePath(root, relPath)]) {
|
|
26801
|
+
mkdirSync2(dirname(abs2), { recursive: true });
|
|
26802
|
+
writeFileSync2(abs2, content);
|
|
26803
|
+
}
|
|
26804
|
+
};
|
|
26805
|
+
var readWorkingFile = (root, relPath) => {
|
|
26806
|
+
try {
|
|
26807
|
+
return readFileSync3(join2(root, relPath), "utf8");
|
|
26808
|
+
} catch {
|
|
26809
|
+
return null;
|
|
26810
|
+
}
|
|
26811
|
+
};
|
|
26812
|
+
var readBaseFile = (root, relPath) => {
|
|
26813
|
+
try {
|
|
26814
|
+
return readFileSync3(basePath(root, relPath), "utf8");
|
|
26815
|
+
} catch {
|
|
26816
|
+
return null;
|
|
26817
|
+
}
|
|
26818
|
+
};
|
|
26819
|
+
var slugify = (name2) => name2.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 60) || "untitled";
|
|
26820
|
+
var localState = (root, resource) => {
|
|
26821
|
+
const changedFiles = [];
|
|
26822
|
+
let missing = false;
|
|
26823
|
+
for (const relPath of resource.files) {
|
|
26824
|
+
const working = readWorkingFile(root, relPath);
|
|
26825
|
+
if (working == null) {
|
|
26826
|
+
missing = true;
|
|
26827
|
+
continue;
|
|
26828
|
+
}
|
|
26829
|
+
if (working !== readBaseFile(root, relPath)) changedFiles.push(relPath);
|
|
26830
|
+
}
|
|
26831
|
+
return {
|
|
26832
|
+
state: missing ? "missing" : changedFiles.length > 0 ? "modified" : "unchanged",
|
|
26833
|
+
changedFiles
|
|
26834
|
+
};
|
|
26835
|
+
};
|
|
26836
|
+
|
|
26532
26837
|
// src/auth.ts
|
|
26533
26838
|
var CALLBACK_TIMEOUT_MS = 5 * 60 * 1e3;
|
|
26534
26839
|
var startCallbackServer = (expectedState) => {
|
|
@@ -26640,110 +26945,35 @@ var signOut = async () => {
|
|
|
26640
26945
|
clearConfig();
|
|
26641
26946
|
process.stdout.write("Signed out.\n");
|
|
26642
26947
|
};
|
|
26643
|
-
var whoami = () => {
|
|
26948
|
+
var whoami = async () => {
|
|
26644
26949
|
const config = readConfig();
|
|
26645
26950
|
if (config == null) {
|
|
26646
26951
|
process.stderr.write("Not signed in. Run `overai signin`.\n");
|
|
26647
26952
|
process.exitCode = 1;
|
|
26648
26953
|
return;
|
|
26649
26954
|
}
|
|
26955
|
+
const cloneOrgId = (() => {
|
|
26956
|
+
try {
|
|
26957
|
+
return readManifest(findWorkspaceRoot()).organizationId;
|
|
26958
|
+
} catch {
|
|
26959
|
+
return null;
|
|
26960
|
+
}
|
|
26961
|
+
})();
|
|
26962
|
+
const effective = orgIdOverride ?? cloneOrgId ?? config.organizationId;
|
|
26963
|
+
const names = await fetchOrgNames().catch(() => null);
|
|
26964
|
+
const label = (id) => names?.get(id) == null ? id : `${id} \u2014 ${String(names.get(id))}`;
|
|
26650
26965
|
process.stdout.write(
|
|
26651
|
-
`Signed in${config.email != null ? ` as ${config.email}` : ""} (org ${
|
|
26966
|
+
`Signed in${config.email != null ? ` as ${config.email}` : ""} (org ${label(effective)}).
|
|
26652
26967
|
`
|
|
26653
26968
|
);
|
|
26654
|
-
|
|
26655
|
-
|
|
26656
|
-
|
|
26657
|
-
|
|
26658
|
-
var flagValue = (args, ...names) => {
|
|
26659
|
-
for (const name2 of names) {
|
|
26660
|
-
const i = args.indexOf(name2);
|
|
26661
|
-
if (i !== -1 && i + 1 < args.length) return args[i + 1];
|
|
26662
|
-
}
|
|
26663
|
-
return void 0;
|
|
26664
|
-
};
|
|
26665
|
-
var stdinClaimedBy = null;
|
|
26666
|
-
var readStdin = async (claimant = "stdin") => {
|
|
26667
|
-
if (stdinClaimedBy != null) {
|
|
26668
|
-
throw new Error(
|
|
26669
|
-
`Only one value can be read from stdin; ${stdinClaimedBy} already consumed it.`
|
|
26670
|
-
);
|
|
26671
|
-
}
|
|
26672
|
-
stdinClaimedBy = claimant;
|
|
26673
|
-
const chunks = [];
|
|
26674
|
-
for await (const chunk of process.stdin) {
|
|
26675
|
-
chunks.push(chunk);
|
|
26676
|
-
}
|
|
26677
|
-
return Buffer.concat(chunks).toString("utf8");
|
|
26678
|
-
};
|
|
26679
|
-
var readValue = async (value, label) => {
|
|
26680
|
-
if (value?.startsWith("@") !== true) return value;
|
|
26681
|
-
if (value.startsWith("@@")) return value.slice(1);
|
|
26682
|
-
const path = value.slice(1);
|
|
26683
|
-
if (path === "-") return (await readStdin(`${label} @-`)).trim();
|
|
26684
|
-
try {
|
|
26685
|
-
return readFileSync2(path, "utf8").trim();
|
|
26686
|
-
} catch {
|
|
26687
|
-
throw new Error(
|
|
26688
|
-
`${label}: could not read file "${path}". Write "@@" to send a literal value starting with "@".`
|
|
26969
|
+
if (effective !== config.organizationId) {
|
|
26970
|
+
process.stdout.write(
|
|
26971
|
+
`Scoped by ${orgIdOverride != null ? "OVERAI_ORG_ID" : ".overai/manifest.json"}; the machine-global active org is ${label(config.organizationId)}.
|
|
26972
|
+
`
|
|
26689
26973
|
);
|
|
26690
26974
|
}
|
|
26691
26975
|
};
|
|
26692
26976
|
|
|
26693
|
-
// src/output.ts
|
|
26694
|
-
var resolveFormat = (explicit) => {
|
|
26695
|
-
if (explicit === "json" || explicit === "csv" || explicit === "table") {
|
|
26696
|
-
return explicit;
|
|
26697
|
-
}
|
|
26698
|
-
if (explicit != null) {
|
|
26699
|
-
throw new Error(
|
|
26700
|
-
`Unknown output format "${explicit}". Use json, table, or csv.`
|
|
26701
|
-
);
|
|
26702
|
-
}
|
|
26703
|
-
return process.stdout.isTTY ? "table" : "json";
|
|
26704
|
-
};
|
|
26705
|
-
var cell = (value) => {
|
|
26706
|
-
if (value == null) return "";
|
|
26707
|
-
if (typeof value === "string") return value;
|
|
26708
|
-
if (typeof value === "number" || typeof value === "boolean" || typeof value === "bigint") {
|
|
26709
|
-
return String(value);
|
|
26710
|
-
}
|
|
26711
|
-
return JSON.stringify(value);
|
|
26712
|
-
};
|
|
26713
|
-
var formatResult = (data, format2) => {
|
|
26714
|
-
if (format2 === "json" || !Array.isArray(data)) {
|
|
26715
|
-
return JSON.stringify(data, null, 2);
|
|
26716
|
-
}
|
|
26717
|
-
const records = data.map(
|
|
26718
|
-
(row) => row != null && typeof row === "object" ? row : { value: row }
|
|
26719
|
-
);
|
|
26720
|
-
if (records.length === 0) return "(no rows)";
|
|
26721
|
-
const columns = [...new Set(records.flatMap((r) => Object.keys(r)))];
|
|
26722
|
-
if (format2 === "csv") {
|
|
26723
|
-
const escape2 = (value) => {
|
|
26724
|
-
const text = cell(value);
|
|
26725
|
-
return /[",\n\r]/.test(text) ? `"${text.replace(/"/g, '""')}"` : text;
|
|
26726
|
-
};
|
|
26727
|
-
return [
|
|
26728
|
-
columns.join(","),
|
|
26729
|
-
...records.map((r) => columns.map((c) => escape2(r[c])).join(","))
|
|
26730
|
-
].join("\n");
|
|
26731
|
-
}
|
|
26732
|
-
const widths = columns.map(
|
|
26733
|
-
(c) => Math.max(c.length, ...records.map((r) => cell(r[c]).length))
|
|
26734
|
-
);
|
|
26735
|
-
const line = (cells) => cells.map((text, i) => text.padEnd(widths[i] ?? 0)).join(" ");
|
|
26736
|
-
return [
|
|
26737
|
-
line(columns),
|
|
26738
|
-
line(widths.map((w) => "-".repeat(w))),
|
|
26739
|
-
...records.map((r) => line(columns.map((c) => cell(r[c]))))
|
|
26740
|
-
].join("\n");
|
|
26741
|
-
};
|
|
26742
|
-
var printResult = (data, format2) => {
|
|
26743
|
-
process.stdout.write(`${formatResult(data, format2)}
|
|
26744
|
-
`);
|
|
26745
|
-
};
|
|
26746
|
-
|
|
26747
26977
|
// src/commands/agent.ts
|
|
26748
26978
|
var runAgent = async (args) => {
|
|
26749
26979
|
const [operation, id] = args;
|
|
@@ -26756,8 +26986,9 @@ var runAgent = async (args) => {
|
|
|
26756
26986
|
headers: { "Content-Type": "application/json" },
|
|
26757
26987
|
body: JSON.stringify({ message })
|
|
26758
26988
|
});
|
|
26759
|
-
const
|
|
26760
|
-
if (!response.ok) throw
|
|
26989
|
+
const raw2 = await response.text();
|
|
26990
|
+
if (!response.ok) throw v2Error("agent generate", response, raw2);
|
|
26991
|
+
const body = JSON.parse(raw2);
|
|
26761
26992
|
printResult(body, resolveFormat(flagValue(args, "-o", "--output")));
|
|
26762
26993
|
};
|
|
26763
26994
|
|
|
@@ -26771,12 +27002,20 @@ var gqlRequest = async (query, variables, options) => {
|
|
|
26771
27002
|
body: JSON.stringify({ query, variables })
|
|
26772
27003
|
}
|
|
26773
27004
|
);
|
|
26774
|
-
const
|
|
27005
|
+
const raw2 = await res.text();
|
|
27006
|
+
const body = (() => {
|
|
27007
|
+
try {
|
|
27008
|
+
return JSON.parse(raw2);
|
|
27009
|
+
} catch {
|
|
27010
|
+
return null;
|
|
27011
|
+
}
|
|
27012
|
+
})();
|
|
26775
27013
|
if (body?.errors != null && body.errors.length > 0) {
|
|
26776
27014
|
throw new Error(body.errors.map((e) => e.message).join("; "));
|
|
26777
27015
|
}
|
|
26778
|
-
if (!res.ok
|
|
26779
|
-
|
|
27016
|
+
if (!res.ok) throw v2Error("graphql", res, raw2);
|
|
27017
|
+
if (body?.data == null) {
|
|
27018
|
+
throw new Error("graphql returned no data and no errors.");
|
|
26780
27019
|
}
|
|
26781
27020
|
return body.data;
|
|
26782
27021
|
};
|
|
@@ -26852,12 +27091,9 @@ var runTrigger = async (automationId, args) => {
|
|
|
26852
27091
|
body: JSON.stringify(body)
|
|
26853
27092
|
}
|
|
26854
27093
|
);
|
|
26855
|
-
const
|
|
26856
|
-
if (!res.ok)
|
|
26857
|
-
|
|
26858
|
-
responseBody?.error ?? `run failed (${String(res.status)})`
|
|
26859
|
-
);
|
|
26860
|
-
}
|
|
27094
|
+
const raw2 = await res.text();
|
|
27095
|
+
if (!res.ok) throw v2Error("automation run", res, raw2);
|
|
27096
|
+
const responseBody = JSON.parse(raw2);
|
|
26861
27097
|
printResult(responseBody, resolveFormat(flagValue(args, "-o", "--output")));
|
|
26862
27098
|
};
|
|
26863
27099
|
var runAutomation = async (args) => {
|
|
@@ -26871,81 +27107,6 @@ var runAutomation = async (args) => {
|
|
|
26871
27107
|
process.exitCode = 1;
|
|
26872
27108
|
};
|
|
26873
27109
|
|
|
26874
|
-
// src/workspace/manifest.ts
|
|
26875
|
-
import { existsSync, mkdirSync as mkdirSync2, readFileSync as readFileSync3, writeFileSync as writeFileSync2 } from "fs";
|
|
26876
|
-
import { dirname, join as join2, resolve } from "path";
|
|
26877
|
-
var MANIFEST_DIR = ".overai";
|
|
26878
|
-
var MANIFEST_FILE = "manifest.json";
|
|
26879
|
-
var BASE_DIR = "base";
|
|
26880
|
-
var findWorkspaceRoot = (from = process.cwd()) => {
|
|
26881
|
-
let dir = resolve(from);
|
|
26882
|
-
for (; ; ) {
|
|
26883
|
-
if (existsSync(join2(dir, MANIFEST_DIR, MANIFEST_FILE))) return dir;
|
|
26884
|
-
const parent = dirname(dir);
|
|
26885
|
-
if (parent === dir) {
|
|
26886
|
-
throw new Error(
|
|
26887
|
-
"Not inside a cloned workspace (no .overai/manifest.json found). Run `overai clone <workspaceId>` first."
|
|
26888
|
-
);
|
|
26889
|
-
}
|
|
26890
|
-
dir = parent;
|
|
26891
|
-
}
|
|
26892
|
-
};
|
|
26893
|
-
var readManifest = (root) => JSON.parse(
|
|
26894
|
-
readFileSync3(join2(root, MANIFEST_DIR, MANIFEST_FILE), "utf8")
|
|
26895
|
-
);
|
|
26896
|
-
var openClone = () => {
|
|
26897
|
-
const root = findWorkspaceRoot();
|
|
26898
|
-
const manifest = readManifest(root);
|
|
26899
|
-
setOrgScope(manifest.organizationId);
|
|
26900
|
-
return { root, manifest };
|
|
26901
|
-
};
|
|
26902
|
-
var writeManifest = (root, manifest) => {
|
|
26903
|
-
mkdirSync2(join2(root, MANIFEST_DIR), { recursive: true });
|
|
26904
|
-
writeFileSync2(
|
|
26905
|
-
join2(root, MANIFEST_DIR, MANIFEST_FILE),
|
|
26906
|
-
`${JSON.stringify(manifest, null, 2)}
|
|
26907
|
-
`
|
|
26908
|
-
);
|
|
26909
|
-
};
|
|
26910
|
-
var basePath = (root, relPath) => join2(root, MANIFEST_DIR, BASE_DIR, relPath);
|
|
26911
|
-
var writeSynced = (root, relPath, content) => {
|
|
26912
|
-
for (const abs2 of [join2(root, relPath), basePath(root, relPath)]) {
|
|
26913
|
-
mkdirSync2(dirname(abs2), { recursive: true });
|
|
26914
|
-
writeFileSync2(abs2, content);
|
|
26915
|
-
}
|
|
26916
|
-
};
|
|
26917
|
-
var readWorkingFile = (root, relPath) => {
|
|
26918
|
-
try {
|
|
26919
|
-
return readFileSync3(join2(root, relPath), "utf8");
|
|
26920
|
-
} catch {
|
|
26921
|
-
return null;
|
|
26922
|
-
}
|
|
26923
|
-
};
|
|
26924
|
-
var readBaseFile = (root, relPath) => {
|
|
26925
|
-
try {
|
|
26926
|
-
return readFileSync3(basePath(root, relPath), "utf8");
|
|
26927
|
-
} catch {
|
|
26928
|
-
return null;
|
|
26929
|
-
}
|
|
26930
|
-
};
|
|
26931
|
-
var slugify = (name2) => name2.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 60) || "untitled";
|
|
26932
|
-
var localState = (root, resource) => {
|
|
26933
|
-
const changedFiles = [];
|
|
26934
|
-
let missing = false;
|
|
26935
|
-
for (const relPath of resource.files) {
|
|
26936
|
-
const working = readWorkingFile(root, relPath);
|
|
26937
|
-
if (working == null) {
|
|
26938
|
-
missing = true;
|
|
26939
|
-
continue;
|
|
26940
|
-
}
|
|
26941
|
-
if (working !== readBaseFile(root, relPath)) changedFiles.push(relPath);
|
|
26942
|
-
}
|
|
26943
|
-
return {
|
|
26944
|
-
state: missing ? "missing" : changedFiles.length > 0 ? "modified" : "unchanged",
|
|
26945
|
-
changedFiles
|
|
26946
|
-
};
|
|
26947
|
-
};
|
|
26948
|
-
|
|
26949
27110
|
// src/workspace/validateElements.ts
|
|
26950
27111
|
var findings = (parsed) => parsed.success ? [] : parsed.error.issues.map((i) => `${i.path.join(".")}: ${i.message}`);
|
|
26951
27112
|
var validateAutomationElements = async (elements) => {
|
|
@@ -26953,7 +27114,7 @@ var validateAutomationElements = async (elements) => {
|
|
|
26953
27114
|
return findings(automationNodesSchema.safeParse(elements));
|
|
26954
27115
|
};
|
|
26955
27116
|
var validateWebPageConfig = async (config) => {
|
|
26956
|
-
const { webPageConfigWriteSchema } = await import("./webPage-
|
|
27117
|
+
const { webPageConfigWriteSchema } = await import("./webPage-G5HIZM7Q.js");
|
|
26957
27118
|
return findings(webPageConfigWriteSchema.safeParse(config));
|
|
26958
27119
|
};
|
|
26959
27120
|
|
|
@@ -27553,10 +27714,9 @@ var enqueueAction = async (runnerId, actionId, inputs, args) => {
|
|
|
27553
27714
|
body: JSON.stringify({ actionId, inputs, actionRunnerId: runnerId })
|
|
27554
27715
|
}
|
|
27555
27716
|
);
|
|
27556
|
-
const
|
|
27557
|
-
if (!res.ok)
|
|
27558
|
-
|
|
27559
|
-
}
|
|
27717
|
+
const raw2 = await res.text();
|
|
27718
|
+
if (!res.ok) throw v2Error("runner run", res, raw2);
|
|
27719
|
+
const body = JSON.parse(raw2);
|
|
27560
27720
|
printResult(body, resolveFormat(flagValue(args, "-o", "--output")));
|
|
27561
27721
|
};
|
|
27562
27722
|
var runRun = async (runnerId, args) => {
|
|
@@ -33361,14 +33521,14 @@ var runDataFile = async (args) => {
|
|
|
33361
33521
|
message: flagValue(args, "-m", "--message") ?? ""
|
|
33362
33522
|
});
|
|
33363
33523
|
const response2 = await fetch(url, { method: "PUT", body: readFileSync5(path) });
|
|
33364
|
-
if (!response2.ok) throw
|
|
33524
|
+
if (!response2.ok) throw v2Error("data-file upload", response2, await response2.text());
|
|
33365
33525
|
process.stdout.write(`${id}
|
|
33366
33526
|
`);
|
|
33367
33527
|
return;
|
|
33368
33528
|
}
|
|
33369
33529
|
const suffix = operation === "head" ? `/head?numLines=${encodeURIComponent(flagValue(args, "--lines") ?? "50")}` : "";
|
|
33370
33530
|
const response = await v2Fetch(`/v2/data-files/${organizationId}/${id}${suffix}`, { redirect: "follow" });
|
|
33371
|
-
if (!response.ok) throw
|
|
33531
|
+
if (!response.ok) throw v2Error(`data-file ${String(operation)}`, response, await response.text());
|
|
33372
33532
|
const bytes = Buffer.from(await response.arrayBuffer());
|
|
33373
33533
|
if (path != null && path !== "-") writeFileSync3(path, bytes);
|
|
33374
33534
|
else process.stdout.write(bytes);
|
|
@@ -33382,11 +33542,11 @@ var runDataStream = async (args) => {
|
|
|
33382
33542
|
}
|
|
33383
33543
|
const { organizationId } = await getAccessToken();
|
|
33384
33544
|
if (operation === "append") {
|
|
33385
|
-
const
|
|
33386
|
-
if (
|
|
33545
|
+
const raw3 = await readValue(args[2], "data stream input");
|
|
33546
|
+
if (raw3 == null) throw new Error("Data stream append requires JSON, @<file>, or @-.");
|
|
33387
33547
|
const parsed = (() => {
|
|
33388
33548
|
try {
|
|
33389
|
-
return JSON.parse(
|
|
33549
|
+
return JSON.parse(raw3);
|
|
33390
33550
|
} catch {
|
|
33391
33551
|
throw new Error("Data stream input must be valid JSON.");
|
|
33392
33552
|
}
|
|
@@ -33396,8 +33556,9 @@ var runDataStream = async (args) => {
|
|
|
33396
33556
|
headers: { "Content-Type": "application/json" },
|
|
33397
33557
|
body: JSON.stringify({ data: Array.isArray(parsed) ? parsed : [parsed] })
|
|
33398
33558
|
});
|
|
33399
|
-
const
|
|
33400
|
-
if (!response2.ok) throw
|
|
33559
|
+
const appended = await response2.text();
|
|
33560
|
+
if (!response2.ok) throw v2Error("data-stream append", response2, appended);
|
|
33561
|
+
const body2 = JSON.parse(appended);
|
|
33401
33562
|
printResult(body2, resolveFormat(flagValue(args, "-o", "--output")));
|
|
33402
33563
|
return;
|
|
33403
33564
|
}
|
|
@@ -33408,8 +33569,9 @@ var runDataStream = async (args) => {
|
|
|
33408
33569
|
const limit2 = flagValue(args, "--limit");
|
|
33409
33570
|
if (limit2 != null) query.set("limit", limit2);
|
|
33410
33571
|
const response = await v2Fetch(`/v1/data-streams/${organizationId}/${id}?${query.toString()}`);
|
|
33411
|
-
const
|
|
33412
|
-
if (!response.ok) throw
|
|
33572
|
+
const raw2 = await response.text();
|
|
33573
|
+
if (!response.ok) throw v2Error("data-stream query", response, raw2);
|
|
33574
|
+
const body = JSON.parse(raw2);
|
|
33413
33575
|
printResult(body, resolveFormat(flagValue(args, "-o", "--output")));
|
|
33414
33576
|
};
|
|
33415
33577
|
|
|
@@ -34112,18 +34274,7 @@ var runFn = async (args) => {
|
|
|
34112
34274
|
`);
|
|
34113
34275
|
}
|
|
34114
34276
|
const body = await res.text();
|
|
34115
|
-
if (!res.ok)
|
|
34116
|
-
const structured = (() => {
|
|
34117
|
-
try {
|
|
34118
|
-
return JSON.parse(body);
|
|
34119
|
-
} catch {
|
|
34120
|
-
return null;
|
|
34121
|
-
}
|
|
34122
|
-
})();
|
|
34123
|
-
throw new Error(
|
|
34124
|
-
structured?.error ?? (body.trim() || `fn failed (${String(res.status)})`)
|
|
34125
|
-
);
|
|
34126
|
-
}
|
|
34277
|
+
if (!res.ok) throw v2Error("fn", res, body);
|
|
34127
34278
|
process.stdout.write(`${body}
|
|
34128
34279
|
`);
|
|
34129
34280
|
};
|
|
@@ -34165,12 +34316,20 @@ var runGraphql = async (args) => {
|
|
|
34165
34316
|
body: JSON.stringify({ query, variables })
|
|
34166
34317
|
}
|
|
34167
34318
|
);
|
|
34168
|
-
const
|
|
34319
|
+
const raw2 = await res.text();
|
|
34320
|
+
const body = (() => {
|
|
34321
|
+
try {
|
|
34322
|
+
return JSON.parse(raw2);
|
|
34323
|
+
} catch {
|
|
34324
|
+
return null;
|
|
34325
|
+
}
|
|
34326
|
+
})();
|
|
34169
34327
|
if (body?.errors != null && body.errors.length > 0) {
|
|
34170
34328
|
throw new Error(body.errors.map((e) => e.message).join("; "));
|
|
34171
34329
|
}
|
|
34172
|
-
if (!res.ok
|
|
34173
|
-
|
|
34330
|
+
if (!res.ok) throw v2Error("graphql", res, raw2);
|
|
34331
|
+
if (body == null) {
|
|
34332
|
+
throw new Error("graphql returned an unreadable body.");
|
|
34174
34333
|
}
|
|
34175
34334
|
printResult(body.data, resolveFormat(flagValue(args, "-o", "--output")));
|
|
34176
34335
|
};
|
|
@@ -34262,71 +34421,6 @@ var runOpen = async (args) => {
|
|
|
34262
34421
|
openBrowser(url);
|
|
34263
34422
|
};
|
|
34264
34423
|
|
|
34265
|
-
// src/commands/org.ts
|
|
34266
|
-
var USER_ORGS_QUERY = `
|
|
34267
|
-
query UserOrganizations($identityId: String!) {
|
|
34268
|
-
identityOrganizations(
|
|
34269
|
-
where: { identityId: { _eq: $identityId }, disabled: { _eq: false } }
|
|
34270
|
-
) {
|
|
34271
|
-
organization { id name }
|
|
34272
|
-
}
|
|
34273
|
-
}
|
|
34274
|
-
`;
|
|
34275
|
-
var listOrgs = async (args) => {
|
|
34276
|
-
const auth = await getAccessToken();
|
|
34277
|
-
const identityId = decodeJwtClaims(auth.token).user_id;
|
|
34278
|
-
if (identityId == null) {
|
|
34279
|
-
throw new Error("Could not read identity from the current session.");
|
|
34280
|
-
}
|
|
34281
|
-
const res = await v2Fetch("/v1/graphql", {
|
|
34282
|
-
method: "POST",
|
|
34283
|
-
headers: { "Content-Type": "application/json" },
|
|
34284
|
-
body: JSON.stringify({ query: USER_ORGS_QUERY, variables: { identityId } })
|
|
34285
|
-
});
|
|
34286
|
-
const body = await res.json().catch(() => null);
|
|
34287
|
-
if (body?.errors != null && body.errors.length > 0) {
|
|
34288
|
-
throw new Error(body.errors.map((e) => e.message).join("; "));
|
|
34289
|
-
}
|
|
34290
|
-
if (!res.ok || body == null) {
|
|
34291
|
-
throw new Error(`org list failed (${String(res.status)})`);
|
|
34292
|
-
}
|
|
34293
|
-
const orgs = (body.data?.identityOrganizations ?? []).map((edge) => edge.organization).filter((org) => org != null).map((org) => ({
|
|
34294
|
-
id: org.id,
|
|
34295
|
-
name: org.name ?? "",
|
|
34296
|
-
active: org.id === auth.organizationId
|
|
34297
|
-
}));
|
|
34298
|
-
printResult(orgs, resolveFormat(flagValue(args, "-o", "--output")));
|
|
34299
|
-
};
|
|
34300
|
-
var switchOrg = async (orgId) => {
|
|
34301
|
-
const config = readConfig();
|
|
34302
|
-
if (config == null) {
|
|
34303
|
-
process.stderr.write("Not signed in. Run `overai signin`.\n");
|
|
34304
|
-
process.exitCode = 1;
|
|
34305
|
-
return;
|
|
34306
|
-
}
|
|
34307
|
-
const result = await exchangeSessionToken(config.refreshToken, orgId);
|
|
34308
|
-
if (result.type === "redirect") {
|
|
34309
|
-
process.stdout.write(
|
|
34310
|
-
`This organization requires SSO. Complete sign-in in your browser, then run \`overai signin\`.
|
|
34311
|
-
${result.redirectUrl}
|
|
34312
|
-
`
|
|
34313
|
-
);
|
|
34314
|
-
openBrowser(result.redirectUrl);
|
|
34315
|
-
process.exitCode = 1;
|
|
34316
|
-
return;
|
|
34317
|
-
}
|
|
34318
|
-
writeConfig({
|
|
34319
|
-
...config,
|
|
34320
|
-
organizationId: orgId,
|
|
34321
|
-
email: decodeJwtClaims(result.token).email ?? config.email,
|
|
34322
|
-
accessToken: result.token,
|
|
34323
|
-
accessTokenExpiresAt: Date.now() + result.accessTokenValiditySeconds * 1e3,
|
|
34324
|
-
refreshToken: result.refreshToken
|
|
34325
|
-
});
|
|
34326
|
-
process.stdout.write(`Switched to org ${orgId}.
|
|
34327
|
-
`);
|
|
34328
|
-
};
|
|
34329
|
-
|
|
34330
34424
|
// src/commands/printablePage.ts
|
|
34331
34425
|
var runPrintablePage = async (args) => {
|
|
34332
34426
|
const [operation, id] = args;
|
|
@@ -34346,8 +34440,9 @@ var runPrintablePage = async (args) => {
|
|
|
34346
34440
|
body: JSON.stringify({ actionId: "PRINTABLE_PAGE_TO_PDF", inputs: { printablePageId: id, searchParams, includeDiagnostics: true } }),
|
|
34347
34441
|
signal: AbortSignal.timeout(timeoutMs)
|
|
34348
34442
|
});
|
|
34349
|
-
const
|
|
34350
|
-
if (!response.ok) throw
|
|
34443
|
+
const raw2 = await response.text();
|
|
34444
|
+
if (!response.ok) throw v2Error("printable-page render", response, raw2);
|
|
34445
|
+
const body = JSON.parse(raw2);
|
|
34351
34446
|
printResult(body, resolveFormat(flagValue(args, "-o", "--output")));
|
|
34352
34447
|
};
|
|
34353
34448
|
|
|
@@ -34609,7 +34704,8 @@ deploy\` makes it live. Pick primitives by trigger:
|
|
|
34609
34704
|
- Awaitable server-side logic, callable from pages/automations/agents \u2192 a
|
|
34610
34705
|
**Function** (Deno sandbox, can import from esm.sh, full env SDK).
|
|
34611
34706
|
- Storage: **TableSpaces** (Postgres, via env.TBSxxx) for structured data;
|
|
34612
|
-
**Data Files** (env.DFxxx) for versioned single-file datasets
|
|
34707
|
+
**Data Files** (env.DFxxx) for versioned single-file datasets; **File
|
|
34708
|
+
Buckets** (env.FBxxx) for browsable file collections and SFTP. Prefer
|
|
34613
34709
|
first-class platform features over third-party integrations.
|
|
34614
34710
|
|
|
34615
34711
|
When broken or unexplained platform behavior blocks progress, send a detailed
|
|
@@ -34629,16 +34725,22 @@ column autocomplete; joins/aggregates/projections take a hand-written type or
|
|
|
34629
34725
|
Pick<...>), env.FNxxx.call()
|
|
34630
34726
|
(pass \`path\` to hit a sub-path of a function that routes internally),
|
|
34631
34727
|
env.ATxxx.start(inputs?) (fire-and-forget), env.DFxxx.read.json()/.saveVersion(),
|
|
34728
|
+
env.FBxxx.list()/read(entryId)/upload()/createFolder(),
|
|
34632
34729
|
env.STORAGE.fetch/upload/presign (upload shortens stored names over 128
|
|
34633
|
-
characters in the middle while preserving their ends),
|
|
34730
|
+
characters in the middle while preserving their ends), env.STORAGE.text
|
|
34731
|
+
(best-effort text representation of PDF, DOCX, Excel, HTML, and text files
|
|
34732
|
+
without AI; \`{ vision: true }\` uses AI to represent PDFs or images as text and
|
|
34733
|
+
is required for images), env.STORAGE.csv (one Excel worksheet selected by name
|
|
34734
|
+
or zero-based index), env.STORAGE.image (PNG representation of a raster image,
|
|
34735
|
+
SVG, or single-page PDF),
|
|
34634
34736
|
env.AI.generateText/generateObject,
|
|
34635
34737
|
env.GRAPHQL.request().
|
|
34636
34738
|
|
|
34637
34739
|
Not everything is available everywhere. Functions and automation code nodes
|
|
34638
34740
|
also get env.STORAGE.zipTree/zipExtract \u2014 list a zip without decompressing it,
|
|
34639
|
-
then extract only the entries you need, each into its own storage URL.
|
|
34640
|
-
|
|
34641
|
-
|
|
34741
|
+
then extract only the entries you need, each into its own storage URL. A web
|
|
34742
|
+
page does NOT have these server-side conversion and archive helpers: that work
|
|
34743
|
+
belongs in a function the page calls.`;
|
|
34642
34744
|
var automations = `# Automation best practices
|
|
34643
34745
|
|
|
34644
34746
|
An automation's elements document is the node graph: an array of nodes, each
|
|
@@ -34775,11 +34877,34 @@ var workflow = `# CLI editing workflow
|
|
|
34775
34877
|
|
|
34776
34878
|
Never edit .overai/ by hand \u2014 it holds the manifest and pristine base copies
|
|
34777
34879
|
that make status/diff/fast-forward work.`;
|
|
34880
|
+
var tablespaces = `# TableSpace best practices
|
|
34881
|
+
|
|
34882
|
+
TableSpaces are isolated PostgreSQL databases. Use PostgreSQL syntax and the
|
|
34883
|
+
generated env.TBSxxx client from pages, functions, and automation code.
|
|
34884
|
+
|
|
34885
|
+
- \`overai sql <tableSpaceId>\` runs SQL through OverAI's authenticated,
|
|
34886
|
+
audited HTTP surface. This is the normal interactive CLI path.
|
|
34887
|
+
- \`overai sql credential create <tableSpaceId> --name <name>\` creates a
|
|
34888
|
+
durable \`postgresql://\` connection string for standard database clients.
|
|
34889
|
+
The CLI prints a PostgreSQL 16+ libpq URL with
|
|
34890
|
+
\`sslmode=verify-full&sslrootcert=system\`. Older libpq clients must point
|
|
34891
|
+
\`sslrootcert\` at a trusted CA file. Other drivers should use the host,
|
|
34892
|
+
port, database, username, and secret with hostname and certificate
|
|
34893
|
+
verification enabled through that driver's TLS settings.
|
|
34894
|
+
It expires after one year unless \`--expires-in <days>\` or \`--never\` is
|
|
34895
|
+
supplied and permitted by organization policy.
|
|
34896
|
+
- Give each service its own credential. List, rotate, or revoke it with
|
|
34897
|
+
\`overai sql credential list|rotate|revoke\`.
|
|
34898
|
+
- The generated secret is the PostgreSQL password. Account passwords, PATs,
|
|
34899
|
+
and JWTs are not accepted. Create and rotate show the secret once.
|
|
34900
|
+
- Rotation, expiration, and revocation reject new connections. Existing
|
|
34901
|
+
sessions continue until disconnect.`;
|
|
34778
34902
|
var BEST_PRACTICES = {
|
|
34779
34903
|
platform: platform2,
|
|
34780
34904
|
automations,
|
|
34781
34905
|
pages,
|
|
34782
34906
|
functions,
|
|
34907
|
+
tablespaces,
|
|
34783
34908
|
workflow
|
|
34784
34909
|
};
|
|
34785
34910
|
|
|
@@ -34986,6 +35111,112 @@ var runReview = async () => {
|
|
|
34986
35111
|
|
|
34987
35112
|
// src/commands/sql.ts
|
|
34988
35113
|
import { createInterface } from "readline";
|
|
35114
|
+
|
|
35115
|
+
// src/commands/sqlCredential.ts
|
|
35116
|
+
var connectionString = async (tableSpaceId, secret) => {
|
|
35117
|
+
const response = await v2Fetch("/v2/cluster-info");
|
|
35118
|
+
const body = await response.json();
|
|
35119
|
+
return `postgresql://overai:${encodeURIComponent(secret)}@${body.postgres.host}:${String(body.postgres.port)}/${tableSpaceId}?sslmode=${body.postgres.sslMode}${body.postgres.sslMode === "verify-full" ? "&sslrootcert=system" : ""}`;
|
|
35120
|
+
};
|
|
35121
|
+
var credentialTableSpaceId = async (credentialId) => {
|
|
35122
|
+
const data = await gqlRequest(
|
|
35123
|
+
`query TableSpaceCredential($id: String!) {
|
|
35124
|
+
tableSpaceCredential(id: $id) { tableSpaceId }
|
|
35125
|
+
}`,
|
|
35126
|
+
{ id: credentialId }
|
|
35127
|
+
);
|
|
35128
|
+
if (!data.tableSpaceCredential) {
|
|
35129
|
+
throw new Error("Credential not found or you lack access to it");
|
|
35130
|
+
}
|
|
35131
|
+
return data.tableSpaceCredential.tableSpaceId;
|
|
35132
|
+
};
|
|
35133
|
+
var runSqlCredential = async (args) => {
|
|
35134
|
+
const [action, id] = args;
|
|
35135
|
+
if (!action || !id) {
|
|
35136
|
+
throw new Error(
|
|
35137
|
+
"Usage: overai sql credential create|list <tableSpaceId> | rotate|revoke <credentialId>"
|
|
35138
|
+
);
|
|
35139
|
+
}
|
|
35140
|
+
if (action === "create") {
|
|
35141
|
+
const tableSpaceId = id;
|
|
35142
|
+
const name2 = flagValue(args, "--name");
|
|
35143
|
+
if (!name2) throw new Error("create requires --name <name>");
|
|
35144
|
+
const expiresIn = flagValue(args, "--expires-in");
|
|
35145
|
+
if (expiresIn && args.includes("--never")) {
|
|
35146
|
+
throw new Error("Use either --expires-in <days> or --never, not both");
|
|
35147
|
+
}
|
|
35148
|
+
const days = expiresIn ? Number(expiresIn) : 365;
|
|
35149
|
+
if (!args.includes("--never") && (!Number.isInteger(days) || days < 1)) {
|
|
35150
|
+
throw new Error("--expires-in must be a positive whole number of days");
|
|
35151
|
+
}
|
|
35152
|
+
const data = await gqlRequest(
|
|
35153
|
+
`mutation CreateTableSpaceCredential($tableSpaceId: String!, $name: String!, $validUntil: Datetime) {
|
|
35154
|
+
createTableSpaceCredential(input: { tableSpaceId: $tableSpaceId, name: $name, validUntil: $validUntil }) { result }
|
|
35155
|
+
}`,
|
|
35156
|
+
{
|
|
35157
|
+
tableSpaceId,
|
|
35158
|
+
name: name2,
|
|
35159
|
+
validUntil: args.includes("--never") ? null : new Date(Date.now() + days * 864e5).toISOString()
|
|
35160
|
+
}
|
|
35161
|
+
);
|
|
35162
|
+
const result = data.createTableSpaceCredential?.result;
|
|
35163
|
+
if (!result) throw new Error("The server did not return a credential");
|
|
35164
|
+
process.stdout.write(
|
|
35165
|
+
`${await connectionString(tableSpaceId, result.secret)}
|
|
35166
|
+
`
|
|
35167
|
+
);
|
|
35168
|
+
return;
|
|
35169
|
+
}
|
|
35170
|
+
if (action === "list") {
|
|
35171
|
+
const tableSpaceId = id;
|
|
35172
|
+
const data = await gqlRequest(
|
|
35173
|
+
`query TableSpaceCredentials($tableSpaceId: String!) {
|
|
35174
|
+
tableSpaceCredentials(condition: { tableSpaceId: $tableSpaceId }) {
|
|
35175
|
+
nodes { id name validUntil lastUsedAt createdAt }
|
|
35176
|
+
}
|
|
35177
|
+
}`,
|
|
35178
|
+
{ tableSpaceId }
|
|
35179
|
+
);
|
|
35180
|
+
printResult(
|
|
35181
|
+
data.tableSpaceCredentials?.nodes ?? [],
|
|
35182
|
+
resolveFormat(flagValue(args, "-o", "--output"))
|
|
35183
|
+
);
|
|
35184
|
+
return;
|
|
35185
|
+
}
|
|
35186
|
+
if (action === "rotate") {
|
|
35187
|
+
const credentialId = id;
|
|
35188
|
+
const tableSpaceId = await credentialTableSpaceId(credentialId);
|
|
35189
|
+
const data = await gqlRequest(
|
|
35190
|
+
`mutation RotateTableSpaceCredential($credentialId: String!) {
|
|
35191
|
+
rotateTableSpaceCredential(input: { credentialId: $credentialId }) { result }
|
|
35192
|
+
}`,
|
|
35193
|
+
{ credentialId }
|
|
35194
|
+
);
|
|
35195
|
+
const secret = data.rotateTableSpaceCredential?.result;
|
|
35196
|
+
if (!secret) throw new Error("The server did not return a credential");
|
|
35197
|
+
process.stdout.write(`${await connectionString(tableSpaceId, secret)}
|
|
35198
|
+
`);
|
|
35199
|
+
return;
|
|
35200
|
+
}
|
|
35201
|
+
if (action === "revoke") {
|
|
35202
|
+
const credentialId = id;
|
|
35203
|
+
await credentialTableSpaceId(credentialId);
|
|
35204
|
+
await gqlRequest(
|
|
35205
|
+
`mutation RevokeTableSpaceCredential($id: String!, $validUntil: Datetime!) {
|
|
35206
|
+
updateTableSpaceCredential(input: { id: $id, patch: { validUntil: $validUntil } }) {
|
|
35207
|
+
tableSpaceCredential { id }
|
|
35208
|
+
}
|
|
35209
|
+
}`,
|
|
35210
|
+
{ id: credentialId, validUntil: (/* @__PURE__ */ new Date()).toISOString() }
|
|
35211
|
+
);
|
|
35212
|
+
process.stdout.write(`${credentialId} revoked
|
|
35213
|
+
`);
|
|
35214
|
+
return;
|
|
35215
|
+
}
|
|
35216
|
+
throw new Error(`Unknown credential action: ${action}`);
|
|
35217
|
+
};
|
|
35218
|
+
|
|
35219
|
+
// src/commands/sql.ts
|
|
34989
35220
|
var runQuery = async (organizationId, tableSpaceId, query, params) => {
|
|
34990
35221
|
const res = await v2Fetch(
|
|
34991
35222
|
`/v2/table-spaces/${organizationId}/${tableSpaceId}/run`,
|
|
@@ -35005,11 +35236,7 @@ var runQuery = async (organizationId, tableSpaceId, query, params) => {
|
|
|
35005
35236
|
return null;
|
|
35006
35237
|
}
|
|
35007
35238
|
})();
|
|
35008
|
-
if (!res.ok || body?.ok === false)
|
|
35009
|
-
throw new Error(
|
|
35010
|
-
body?.error ?? (raw2.trim().length > 0 ? raw2.trim() : res.status === 404 ? "table space not found or you lack access to it" : `HTTP ${String(res.status)}`)
|
|
35011
|
-
);
|
|
35012
|
-
}
|
|
35239
|
+
if (!res.ok || body?.ok === false) throw v2Error("sql", res, raw2);
|
|
35013
35240
|
return {
|
|
35014
35241
|
rows: body?.rows ?? [],
|
|
35015
35242
|
rowCount: body?.rowCount ?? 0,
|
|
@@ -35135,6 +35362,9 @@ var runRepl = async (organizationId, tableSpaceId, format2) => {
|
|
|
35135
35362
|
});
|
|
35136
35363
|
};
|
|
35137
35364
|
var runSql = async (args) => {
|
|
35365
|
+
if (args[0] === "credential") {
|
|
35366
|
+
return runSqlCredential(args.slice(1));
|
|
35367
|
+
}
|
|
35138
35368
|
const tableSpaceId = args[0];
|
|
35139
35369
|
if (tableSpaceId == null || tableSpaceId.startsWith("-")) {
|
|
35140
35370
|
throw new Error(
|
|
@@ -35461,20 +35691,9 @@ var runDiff = async (args) => {
|
|
|
35461
35691
|
};
|
|
35462
35692
|
|
|
35463
35693
|
// src/commands/workspace.ts
|
|
35464
|
-
var workspaceIdFrom = (args) =>
|
|
35465
|
-
|
|
35466
|
-
|
|
35467
|
-
);
|
|
35468
|
-
if (workspaceId == null) return openClone().manifest.workspaceId;
|
|
35469
|
-
try {
|
|
35470
|
-
openClone();
|
|
35471
|
-
} catch (error) {
|
|
35472
|
-
if (!(error instanceof Error) || !error.message.startsWith("Not inside a cloned workspace")) {
|
|
35473
|
-
throw error;
|
|
35474
|
-
}
|
|
35475
|
-
}
|
|
35476
|
-
return workspaceId;
|
|
35477
|
-
};
|
|
35694
|
+
var workspaceIdFrom = (args) => args.find(
|
|
35695
|
+
(arg, index) => !arg.startsWith("-") && args[index - 1] !== "-o" && args[index - 1] !== "--output"
|
|
35696
|
+
) ?? openClone().manifest.workspaceId;
|
|
35478
35697
|
var listWorkspaces = async (args) => {
|
|
35479
35698
|
const archived = args.includes("--archived");
|
|
35480
35699
|
const limit2 = Number(flagValue(args, "--limit") ?? 200);
|
|
@@ -35514,10 +35733,7 @@ var showWorkspace = async (args) => {
|
|
|
35514
35733
|
`Workspace ${workspaceId} not found (or not visible to you).`
|
|
35515
35734
|
);
|
|
35516
35735
|
}
|
|
35517
|
-
printResult(
|
|
35518
|
-
data.workspace,
|
|
35519
|
-
resolveFormat(flagValue(args, "-o", "--output"))
|
|
35520
|
-
);
|
|
35736
|
+
printResult(data.workspace, resolveFormat(flagValue(args, "-o", "--output")));
|
|
35521
35737
|
};
|
|
35522
35738
|
var listWorkspaceUsers = async (args) => {
|
|
35523
35739
|
const workspaceId = workspaceIdFrom(args);
|
|
@@ -35553,9 +35769,7 @@ var listWorkspaceUsers = async (args) => {
|
|
|
35553
35769
|
parentWorkspaceRole: membership.parentWorkspaceRole ?? ""
|
|
35554
35770
|
}
|
|
35555
35771
|
]
|
|
35556
|
-
).sort(
|
|
35557
|
-
(a, b) => (a.name || a.email).localeCompare(b.name || b.email)
|
|
35558
|
-
),
|
|
35772
|
+
).sort((a, b) => (a.name || a.email).localeCompare(b.name || b.email)),
|
|
35559
35773
|
resolveFormat(flagValue(args, "-o", "--output"))
|
|
35560
35774
|
);
|
|
35561
35775
|
};
|
|
@@ -35608,6 +35822,10 @@ Usage:
|
|
|
35608
35822
|
Execution history / logs
|
|
35609
35823
|
overai sql <tableSpaceId> ["<SQL>"] Run SQL against a tablespace; no query
|
|
35610
35824
|
opens a psql-style session (stdin scripts work)
|
|
35825
|
+
overai sql credential create <tableSpaceId> --name <name> [--expires-in <days>|--never]
|
|
35826
|
+
Create a durable PostgreSQL connection string
|
|
35827
|
+
overai sql credential list <tableSpaceId>
|
|
35828
|
+
overai sql credential rotate|revoke <credentialId>
|
|
35611
35829
|
|
|
35612
35830
|
Workspace sync (edit resources as local files):
|
|
35613
35831
|
overai clone <workspaceId> [dir] Materialize resources and WORKSPACE.md
|
|
@@ -35667,16 +35885,43 @@ it from stdin. Prefer that for anything long or quote-heavy: an inline value is
|
|
|
35667
35885
|
parsed by your shell first, and one apostrophe inside it silently truncates the
|
|
35668
35886
|
rest. Write @@ to send a literal value that starts with "@".
|
|
35669
35887
|
|
|
35888
|
+
Organizations: commands run as the clone you're standing in (.overai/manifest.json),
|
|
35889
|
+
else the active org from \`org switch\`. The active org is machine-global \u2014 every
|
|
35890
|
+
shell shares it \u2014 so scope one command or one shell with OVERAI_ORG_ID=<orgId>
|
|
35891
|
+
instead. \`overai whoami\` says which org is in effect and why.
|
|
35892
|
+
|
|
35670
35893
|
Output: table on a TTY, JSON when piped; -o json|table|csv to force.
|
|
35671
35894
|
Aliases: login = signin, logout = signout, ws = workspace.
|
|
35672
35895
|
Env: OVERAI_API_URL, OVERAI_APP_URL override the target deployment.
|
|
35896
|
+
OVERAI_ORG_ID overrides the organization for this shell.
|
|
35673
35897
|
`;
|
|
35674
35898
|
process.stdout.on("error", (error) => {
|
|
35675
35899
|
if (error.code === "EPIPE") process.exit(0);
|
|
35676
35900
|
throw error;
|
|
35677
35901
|
});
|
|
35902
|
+
var ORG_AGNOSTIC_COMMANDS = /* @__PURE__ */ new Set([
|
|
35903
|
+
"signin",
|
|
35904
|
+
"login",
|
|
35905
|
+
"signout",
|
|
35906
|
+
"logout",
|
|
35907
|
+
"whoami",
|
|
35908
|
+
"org",
|
|
35909
|
+
"clone",
|
|
35910
|
+
"update",
|
|
35911
|
+
"upgrade",
|
|
35912
|
+
"version",
|
|
35913
|
+
"--version",
|
|
35914
|
+
"-v",
|
|
35915
|
+
"help",
|
|
35916
|
+
"--help",
|
|
35917
|
+
"-h"
|
|
35918
|
+
]);
|
|
35678
35919
|
var run = async () => {
|
|
35679
35920
|
const [command, ...rest] = process.argv.slice(2);
|
|
35921
|
+
if (command != null && !ORG_AGNOSTIC_COMMANDS.has(command)) {
|
|
35922
|
+
pinOrgFromClone();
|
|
35923
|
+
announceOrgScope();
|
|
35924
|
+
}
|
|
35680
35925
|
switch (command) {
|
|
35681
35926
|
case "signin":
|
|
35682
35927
|
case "login":
|
|
@@ -35687,7 +35932,7 @@ var run = async () => {
|
|
|
35687
35932
|
await signOut();
|
|
35688
35933
|
return;
|
|
35689
35934
|
case "whoami":
|
|
35690
|
-
whoami();
|
|
35935
|
+
await whoami();
|
|
35691
35936
|
return;
|
|
35692
35937
|
case "org":
|
|
35693
35938
|
if (rest[0] === "list") {
|