@overaihq/cli 0.10.3 → 0.11.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +12 -1
- package/dist/index.js +95 -36
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -20,7 +20,7 @@ overai workspace list # find a workspace id
|
|
|
20
20
|
overai workspace show <id> # read its name and overview
|
|
21
21
|
overai workspace users <id> # list users and direct/inherited roles
|
|
22
22
|
overai create agent --workspace <id> --name "Support agent"
|
|
23
|
-
overai clone <workspaceId> #
|
|
23
|
+
overai clone <workspaceId> # clone the workspace and its descendants
|
|
24
24
|
# ...edit files...
|
|
25
25
|
overai status # local edits + remote drift
|
|
26
26
|
overai diff # what changed
|
|
@@ -36,6 +36,17 @@ Run `overai help` for the full command list, including function invocation,
|
|
|
36
36
|
automation runs and per-node state, tablespace SQL (a psql-style REPL), and
|
|
37
37
|
`overai dev` for live-previewing a web page from local files.
|
|
38
38
|
|
|
39
|
+
Clone includes accessible, non-archived descendants in nested
|
|
40
|
+
`workspaces/<slug>.<workspaceId>/` folders. Each workspace has its own
|
|
41
|
+
`.overai/manifest.json`, resource files, and `WORKSPACE.md`. Existing resource
|
|
42
|
+
filenames and the top-level clone directory stay unchanged.
|
|
43
|
+
|
|
44
|
+
Commands use the nearest workspace folder: `cd` into a child to edit or sync it.
|
|
45
|
+
`status`, `pull`, `push`, `deploy`, and `restore` still affect only that workspace,
|
|
46
|
+
not its descendants. Pull does not discover new child workspaces. Clone those
|
|
47
|
+
separately, or clone the parent into a fresh directory. Local file moves never
|
|
48
|
+
move resources between workspaces in OverAI.
|
|
49
|
+
|
|
39
50
|
Inside a clone, `workspace show` and `workspace users` infer the workspace id.
|
|
40
51
|
`WORKSPACE.md` is the overview captured when the clone is created; use
|
|
41
52
|
`workspace show` when you need the current server value.
|
package/dist/index.js
CHANGED
|
@@ -26713,12 +26713,19 @@ var getAccessToken = async () => {
|
|
|
26713
26713
|
);
|
|
26714
26714
|
deployment.pending = omit(deployment.pending, target.organizationId);
|
|
26715
26715
|
writeStore(store);
|
|
26716
|
+
if (response?.reason === "mfa_setup_required") return response;
|
|
26716
26717
|
}
|
|
26717
26718
|
throw new InteractiveSignInRequired(
|
|
26718
26719
|
`Org ${target.organizationId} requires browser authorization. ${signin}`
|
|
26719
26720
|
);
|
|
26720
26721
|
})();
|
|
26721
|
-
if (result.type === "redirect")
|
|
26722
|
+
if (result.type === "redirect") {
|
|
26723
|
+
if (result.reason === "mfa_setup_required")
|
|
26724
|
+
throw new Error(
|
|
26725
|
+
`Org ${target.organizationId} requires two-factor authentication. Enroll at ${result.redirectUrl}. ${signin}`
|
|
26726
|
+
);
|
|
26727
|
+
throw new InteractiveSignInRequired(signin);
|
|
26728
|
+
}
|
|
26722
26729
|
const claims = decodeJwtClaims(result.token);
|
|
26723
26730
|
if (claims.org !== target.organizationId || target.identityId != null && claims.user_id !== target.identityId) {
|
|
26724
26731
|
throw new Error(
|
|
@@ -33845,6 +33852,7 @@ import { dirname as dirname3, join as join5 } from "path";
|
|
|
33845
33852
|
// src/commands/sync.ts
|
|
33846
33853
|
import {
|
|
33847
33854
|
existsSync as existsSync3,
|
|
33855
|
+
lstatSync,
|
|
33848
33856
|
mkdirSync as mkdirSync3,
|
|
33849
33857
|
readFileSync as readFileSync6,
|
|
33850
33858
|
unlinkSync,
|
|
@@ -33981,43 +33989,91 @@ var runClone = async (args) => {
|
|
|
33981
33989
|
if (existsSync3(join4(root, "WORKSPACE.md")) && partialCloneWorkspaceId == null) {
|
|
33982
33990
|
throw new Error(`${root} already contains WORKSPACE.md.`);
|
|
33983
33991
|
}
|
|
33984
|
-
const
|
|
33985
|
-
|
|
33986
|
-
|
|
33987
|
-
|
|
33988
|
-
|
|
33989
|
-
|
|
33990
|
-
|
|
33991
|
-
|
|
33992
|
-
|
|
33992
|
+
const pending = [{ workspace, root }];
|
|
33993
|
+
const seen = /* @__PURE__ */ new Set([workspace.id]);
|
|
33994
|
+
const plan = [];
|
|
33995
|
+
for (const entry of pending) {
|
|
33996
|
+
const marker = join4(entry.root, ".overai", "clone-in-progress");
|
|
33997
|
+
const completed = existsSync3(join4(entry.root, ".overai", "manifest.json"));
|
|
33998
|
+
if (entry.root !== root && existsSync3(entry.root)) {
|
|
33999
|
+
if (lstatSync(entry.root).isSymbolicLink())
|
|
34000
|
+
throw new Error(`Refusing to clone into symbolic link ${entry.root}.`);
|
|
34001
|
+
const savedId = completed ? readManifest(entry.root).workspaceId : existsSync3(marker) ? readFileSync6(marker, "utf8").trim() : null;
|
|
34002
|
+
if (partialCloneWorkspaceId !== workspaceId || savedId !== entry.workspace.id)
|
|
34003
|
+
throw new Error(`${entry.root} already exists. Choose another clone directory.`);
|
|
34004
|
+
}
|
|
34005
|
+
if (existsSync3(join4(entry.root, "workspaces")) && lstatSync(join4(entry.root, "workspaces")).isSymbolicLink())
|
|
34006
|
+
throw new Error(`Refusing to clone through symbolic link ${join4(entry.root, "workspaces")}.`);
|
|
34007
|
+
if (!completed) {
|
|
34008
|
+
const resourcesByAdapter = await Promise.all(allAdapters.map(async (adapter) => ({
|
|
34009
|
+
adapter,
|
|
34010
|
+
resources: await adapter.fetchAll(entry.workspace.id)
|
|
34011
|
+
})));
|
|
34012
|
+
plan.push({
|
|
34013
|
+
root: entry.root,
|
|
34014
|
+
description: entry.workspace.description,
|
|
34015
|
+
manifest: {
|
|
34016
|
+
workspaceId: entry.workspace.id,
|
|
34017
|
+
workspaceName: entry.workspace.name,
|
|
34018
|
+
organizationId: entry.workspace.organizationId,
|
|
34019
|
+
resources: {}
|
|
34020
|
+
},
|
|
34021
|
+
resourcesByAdapter
|
|
34022
|
+
});
|
|
34023
|
+
}
|
|
34024
|
+
let after = null;
|
|
34025
|
+
do {
|
|
34026
|
+
const data = await gqlRequest(
|
|
34027
|
+
`query CliCloneChildren($id: String!, $after: Cursor) {
|
|
34028
|
+
workspaceWorkspaces(condition: { parentWorkspaceId: $id }, first: 100, after: $after) {
|
|
34029
|
+
nodes { workspace { id name description organizationId isArchived } }
|
|
34030
|
+
pageInfo { hasNextPage endCursor }
|
|
34031
|
+
}
|
|
34032
|
+
}`,
|
|
34033
|
+
{ id: entry.workspace.id, after }
|
|
34034
|
+
);
|
|
34035
|
+
for (const node of data.workspaceWorkspaces.nodes) {
|
|
34036
|
+
const child = node?.workspace;
|
|
34037
|
+
if (child == null || child.isArchived) continue;
|
|
34038
|
+
if (child.organizationId !== workspace.organizationId || seen.has(child.id))
|
|
34039
|
+
throw new Error(`Invalid workspace hierarchy at ${child.id}.`);
|
|
34040
|
+
if (!/^[a-zA-Z0-9_-]+$/.test(child.id))
|
|
34041
|
+
throw new Error(`Invalid workspace id ${child.id}.`);
|
|
34042
|
+
seen.add(child.id);
|
|
34043
|
+
pending.push({ workspace: child, root: join4(entry.root, "workspaces", `${slugify(child.name)}.${child.id}`) });
|
|
34044
|
+
}
|
|
34045
|
+
const page = data.workspaceWorkspaces.pageInfo;
|
|
34046
|
+
if (page.hasNextPage && (page.endCursor == null || page.endCursor === after))
|
|
34047
|
+
throw new Error("Workspace pagination did not advance.");
|
|
34048
|
+
after = page.hasNextPage ? page.endCursor : null;
|
|
34049
|
+
} while (after != null);
|
|
34050
|
+
}
|
|
34051
|
+
for (const entry of plan) {
|
|
34052
|
+
mkdirSync3(join4(entry.root, ".overai"), { recursive: true });
|
|
34053
|
+
writeFileSync4(join4(entry.root, ".overai", "clone-in-progress"), `${entry.manifest.workspaceId}
|
|
33993
34054
|
`);
|
|
33994
|
-
|
|
33995
|
-
|
|
33996
|
-
|
|
34055
|
+
writeFileSync4(
|
|
34056
|
+
join4(entry.root, "WORKSPACE.md"),
|
|
34057
|
+
entry.description.length === 0 ? "" : `${entry.description.trimEnd()}
|
|
33997
34058
|
`
|
|
33998
|
-
|
|
33999
|
-
|
|
34000
|
-
|
|
34001
|
-
|
|
34002
|
-
|
|
34003
|
-
|
|
34004
|
-
|
|
34005
|
-
for (const { adapter, resources: resources2 } of resourcesByAdapter) {
|
|
34006
|
-
for (const remote of resources2) {
|
|
34007
|
-
for (const [relPath, content] of Object.entries(remote.files)) {
|
|
34008
|
-
writeSynced(root, relPath, content);
|
|
34059
|
+
);
|
|
34060
|
+
for (const { adapter, resources: resources2 } of entry.resourcesByAdapter) {
|
|
34061
|
+
for (const remote of resources2) {
|
|
34062
|
+
for (const [relPath, content] of Object.entries(remote.files)) {
|
|
34063
|
+
writeSynced(entry.root, relPath, content);
|
|
34064
|
+
}
|
|
34065
|
+
entry.manifest.resources[remote.id] = toManifestResource(adapter.type, remote);
|
|
34009
34066
|
}
|
|
34010
|
-
manifest.
|
|
34067
|
+
process.stdout.write(`${entry.manifest.workspaceName}: ${adapter.type}: ${String(resources2.length)} cloned
|
|
34068
|
+
`);
|
|
34011
34069
|
}
|
|
34012
|
-
process.stdout.write(
|
|
34013
|
-
`${adapter.type}: ${String(resources2.length)} cloned
|
|
34014
|
-
`
|
|
34015
|
-
);
|
|
34016
34070
|
}
|
|
34017
|
-
|
|
34018
|
-
|
|
34071
|
+
for (const entry of plan.toReversed()) {
|
|
34072
|
+
writeManifest(entry.root, entry.manifest);
|
|
34073
|
+
unlinkSync(join4(entry.root, ".overai", "clone-in-progress"));
|
|
34074
|
+
}
|
|
34019
34075
|
process.stdout.write(`
|
|
34020
|
-
Cloned "${workspace.name}" into ${root}
|
|
34076
|
+
Cloned "${workspace.name}" and ${String(pending.length - 1)} descendant workspaces into ${root}
|
|
34021
34077
|
`);
|
|
34022
34078
|
};
|
|
34023
34079
|
var collectStatus = async (root, manifest) => {
|
|
@@ -35262,9 +35318,12 @@ executionMemory MB).
|
|
|
35262
35318
|
var workflow = `# CLI editing workflow
|
|
35263
35319
|
|
|
35264
35320
|
1. \`overai workspace list\` to find the id, then \`overai clone <workspaceId>\`
|
|
35265
|
-
(or \`overai pull\` in an existing clone).
|
|
35266
|
-
|
|
35267
|
-
|
|
35321
|
+
(or \`overai pull\` in an existing clone). Clone includes accessible,
|
|
35322
|
+
non-archived descendants under \`workspaces/<slug>.<workspaceId>/\`, each with
|
|
35323
|
+
its own manifest and WORKSPACE.md. Change into a child folder to work there.
|
|
35324
|
+
All sync commands stay scoped to the nearest workspace, never its children.
|
|
35325
|
+
Pull does not discover new children; clone those separately. Moving local
|
|
35326
|
+
files does not move resources between workspaces in OverAI.
|
|
35268
35327
|
2. Edit files. The id in each filename is authoritative; slugs are cosmetic.
|
|
35269
35328
|
3. \`overai status\` / \`overai diff\` \u2014 review what changed.
|
|
35270
35329
|
4. \`overai review\` \u2014 local checks, authenticated TypeScript lint against the
|
|
@@ -36230,7 +36289,7 @@ Usage:
|
|
|
36230
36289
|
overai sql credential rotate|revoke <credentialId>
|
|
36231
36290
|
|
|
36232
36291
|
Workspace sync (edit resources as local files):
|
|
36233
|
-
overai clone <workspaceId> [dir]
|
|
36292
|
+
overai clone <workspaceId> [dir] Clone workspace and accessible descendants
|
|
36234
36293
|
overai status Local edits + remote drift
|
|
36235
36294
|
overai diff [filter] [--from <ref>] [--to <ref>]
|
|
36236
36295
|
Diff versions (refs: N, base, local, deployed, latest;
|