@heyditto/cli 2.4.1 → 2.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +88 -0
- package/dist/cli.js +2 -0
- package/dist/cli.js.map +1 -1
- package/dist/teleport/api.d.ts +139 -0
- package/dist/teleport/api.js +61 -0
- package/dist/teleport/api.js.map +1 -0
- package/dist/teleport/bundle.d.ts +35 -0
- package/dist/teleport/bundle.js +102 -0
- package/dist/teleport/bundle.js.map +1 -0
- package/dist/teleport/chunks.d.ts +13 -0
- package/dist/teleport/chunks.js +57 -0
- package/dist/teleport/chunks.js.map +1 -0
- package/dist/teleport/commands.d.ts +74 -0
- package/dist/teleport/commands.js +488 -0
- package/dist/teleport/commands.js.map +1 -0
- package/dist/teleport/discover.d.ts +13 -0
- package/dist/teleport/discover.js +64 -0
- package/dist/teleport/discover.js.map +1 -0
- package/dist/teleport/git.d.ts +18 -0
- package/dist/teleport/git.js +41 -0
- package/dist/teleport/git.js.map +1 -0
- package/dist/teleport/harness.d.ts +29 -0
- package/dist/teleport/harness.js +121 -0
- package/dist/teleport/harness.js.map +1 -0
- package/dist/teleport/offload.d.ts +32 -0
- package/dist/teleport/offload.js +83 -0
- package/dist/teleport/offload.js.map +1 -0
- package/dist/teleport/pull.d.ts +12 -0
- package/dist/teleport/pull.js +118 -0
- package/dist/teleport/pull.js.map +1 -0
- package/dist/teleport/push.d.ts +49 -0
- package/dist/teleport/push.js +261 -0
- package/dist/teleport/push.js.map +1 -0
- package/dist/teleport/restore.d.ts +16 -0
- package/dist/teleport/restore.js +163 -0
- package/dist/teleport/restore.js.map +1 -0
- package/dist/teleport/storage.d.ts +53 -0
- package/dist/teleport/storage.js +43 -0
- package/dist/teleport/storage.js.map +1 -0
- package/dist/teleport/types.d.ts +100 -0
- package/dist/teleport/types.js +85 -0
- package/dist/teleport/types.js.map +1 -0
- package/dist/teleport/worktree.d.ts +22 -0
- package/dist/teleport/worktree.js +94 -0
- package/dist/teleport/worktree.js.map +1 -0
- package/package.json +1 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pull.js","sourceRoot":"","sources":["../../src/teleport/pull.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import * as tapi from "./api.js";
|
|
2
|
+
import { type HarnessKind, type Manifest } from "./types.js";
|
|
3
|
+
export interface PushInput {
|
|
4
|
+
root: string;
|
|
5
|
+
capsuleId: string;
|
|
6
|
+
parentGeneration: number | null;
|
|
7
|
+
/** Previous generation's manifest, for thin bundles. */
|
|
8
|
+
previousManifest?: Manifest;
|
|
9
|
+
harness: {
|
|
10
|
+
kind: HarnessKind;
|
|
11
|
+
sessionId?: string;
|
|
12
|
+
cwd?: string;
|
|
13
|
+
};
|
|
14
|
+
ignoredIncludes: string[];
|
|
15
|
+
rootName: string;
|
|
16
|
+
rootKind: "repo" | "folder";
|
|
17
|
+
/** Who is committing: the CLI on a user's machine, or the Ditto Code runner. */
|
|
18
|
+
committedBy?: tapi.CommittedBy;
|
|
19
|
+
}
|
|
20
|
+
export interface PushOutput {
|
|
21
|
+
generation: number;
|
|
22
|
+
bytesTotal: number;
|
|
23
|
+
dedupedBytes: number;
|
|
24
|
+
chunkCount: number;
|
|
25
|
+
uploaded: number;
|
|
26
|
+
reused: number;
|
|
27
|
+
/** Bytes actually sent to storage this push. */
|
|
28
|
+
uploadedBytes: number;
|
|
29
|
+
/** Bytes the generation references in total (every chunk, counted once per reference). */
|
|
30
|
+
logicalBytes: number;
|
|
31
|
+
/** logicalBytes − uploadedBytes: what dedup against earlier pushes saved. */
|
|
32
|
+
reusedBytes: number;
|
|
33
|
+
/** reusedBytes / logicalBytes, 0 when nothing was referenced. */
|
|
34
|
+
savingsRatio: number;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Builds a generation, negotiates which chunks are missing, uploads them via
|
|
38
|
+
* presigned PUTs, then commits the manifest. The manifest is content-addressed
|
|
39
|
+
* too, so a re-push with no changes uploads nothing.
|
|
40
|
+
*
|
|
41
|
+
* Every generation's manifest carries each repo's complete pack chain (the
|
|
42
|
+
* basis packs by reference plus this generation's thin pack), so a pull of any
|
|
43
|
+
* generation rebuilds full history from that one manifest. When the server no
|
|
44
|
+
* longer holds a referenced basis chunk, the affected repos are re-bundled in
|
|
45
|
+
* full and the push retried once.
|
|
46
|
+
*/
|
|
47
|
+
export declare function pushCapsule(input: PushInput, forceFull?: Set<string>): Promise<PushOutput>;
|
|
48
|
+
/** The Ditto Code runner authenticates with a ditto_agent_ token and pins the harness session via env. */
|
|
49
|
+
export declare function detectCommitter(): tapi.CommittedBy;
|
|
@@ -0,0 +1,261 @@
|
|
|
1
|
+
import { mkdtemp, rm, writeFile } from "node:fs/promises";
|
|
2
|
+
import os from "node:os";
|
|
3
|
+
import path from "node:path";
|
|
4
|
+
import { packageVersion } from "../config.js";
|
|
5
|
+
import * as tapi from "./api.js";
|
|
6
|
+
import { basisFromPrevious, createBundle, readRepoState } from "./bundle.js";
|
|
7
|
+
import { chunkFile, dedupedBytes, readChunk, sha256 } from "./chunks.js";
|
|
8
|
+
import { discoverRepos } from "./discover.js";
|
|
9
|
+
import { captureHarness, locateHarness } from "./harness.js";
|
|
10
|
+
import { captureWorktree, dirtyPaths, pickCompression } from "./worktree.js";
|
|
11
|
+
import { DEFAULT_EXCLUDES, MANIFEST_VERSION, machineInfo, } from "./types.js";
|
|
12
|
+
const PUT_CONCURRENCY = 4;
|
|
13
|
+
const NEGOTIATE_BATCH = 200;
|
|
14
|
+
/** Thin packs chained past this length are compacted into a fresh full bundle. */
|
|
15
|
+
const MAX_PACK_CHAIN = 8;
|
|
16
|
+
/**
|
|
17
|
+
* Builds a generation, negotiates which chunks are missing, uploads them via
|
|
18
|
+
* presigned PUTs, then commits the manifest. The manifest is content-addressed
|
|
19
|
+
* too, so a re-push with no changes uploads nothing.
|
|
20
|
+
*
|
|
21
|
+
* Every generation's manifest carries each repo's complete pack chain (the
|
|
22
|
+
* basis packs by reference plus this generation's thin pack), so a pull of any
|
|
23
|
+
* generation rebuilds full history from that one manifest. When the server no
|
|
24
|
+
* longer holds a referenced basis chunk, the affected repos are re-bundled in
|
|
25
|
+
* full and the push retried once.
|
|
26
|
+
*/
|
|
27
|
+
export async function pushCapsule(input, forceFull = new Set()) {
|
|
28
|
+
const tmp = await mkdtemp(path.join(os.tmpdir(), "teleport-push-"));
|
|
29
|
+
const compression = pickCompression();
|
|
30
|
+
const generation = (input.parentGeneration ?? 0) + 1;
|
|
31
|
+
const sources = new Map();
|
|
32
|
+
/** Chunks referenced from a previous generation (no local bytes) → their repo. */
|
|
33
|
+
const carried = new Map();
|
|
34
|
+
const allChunks = [];
|
|
35
|
+
try {
|
|
36
|
+
const discovery = await discoverRepos(input.root);
|
|
37
|
+
const prevByRel = new Map();
|
|
38
|
+
for (const r of input.previousManifest?.repos ?? [])
|
|
39
|
+
prevByRel.set(r.relPath, r);
|
|
40
|
+
const repos = [];
|
|
41
|
+
for (const rel of discovery.repos) {
|
|
42
|
+
const repoDir = rel === "." ? discovery.root : path.join(discovery.root, rel);
|
|
43
|
+
const state = readRepoState(repoDir);
|
|
44
|
+
const prev = prevByRel.get(rel);
|
|
45
|
+
// Thin against the previous generation unless forced, unless there is no
|
|
46
|
+
// usable basis, or unless the chain is long enough that a restore would
|
|
47
|
+
// crawl; those cases compact into a fresh full bundle.
|
|
48
|
+
const useBasis = !forceFull.has(rel) && !!prev && prev.packs.length > 0 && prev.packs.length < MAX_PACK_CHAIN;
|
|
49
|
+
const basis = useBasis ? basisFromPrevious(prev) : [];
|
|
50
|
+
const bundleFile = path.join(tmp, `bundle-${safe(rel)}.bundle`);
|
|
51
|
+
const bundle = await createBundle(repoDir, bundleFile, basis, Object.keys(state.upstreamTips).map((u) => `refs/remotes/${u}`));
|
|
52
|
+
const packs = [];
|
|
53
|
+
if (useBasis && (bundle === null || bundle.kind === "thin")) {
|
|
54
|
+
// Carry the basis chain by reference: the server already holds these
|
|
55
|
+
// chunks and dedups them, and a pull needs them to rebuild history.
|
|
56
|
+
for (const pack of prev.packs) {
|
|
57
|
+
packs.push(pack);
|
|
58
|
+
for (const c of pack.chunks) {
|
|
59
|
+
allChunks.push(c);
|
|
60
|
+
if (!sources.has(c.sha256))
|
|
61
|
+
carried.set(c.sha256, rel);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
const packChunks = bundle ? await addFileChunks(bundle.file, sources, allChunks) : [];
|
|
66
|
+
for (const c of packChunks)
|
|
67
|
+
carried.delete(c.sha256);
|
|
68
|
+
const dirty = dirtyPaths(repoDir, input.ignoredIncludes);
|
|
69
|
+
const wtFile = path.join(tmp, `worktree-${safe(rel)}.tar`);
|
|
70
|
+
const capture = await captureWorktree(repoDir, dirty, wtFile, compression);
|
|
71
|
+
const wtChunks = capture ? await addFileChunks(capture.file, sources, allChunks) : [];
|
|
72
|
+
if (bundle) {
|
|
73
|
+
const pack = { kind: bundle.kind, chunks: packChunks };
|
|
74
|
+
if (bundle.kind === "thin" && input.parentGeneration)
|
|
75
|
+
pack.basisGeneration = input.parentGeneration;
|
|
76
|
+
packs.push(pack);
|
|
77
|
+
}
|
|
78
|
+
const repo = {
|
|
79
|
+
head: state.head,
|
|
80
|
+
relPath: rel,
|
|
81
|
+
remotes: state.remotes,
|
|
82
|
+
packs,
|
|
83
|
+
worktree: capture
|
|
84
|
+
? { chunks: wtChunks, entries: capture.entries, bytes: bundleBytes(wtChunks) }
|
|
85
|
+
: { chunks: [], entries: 0, bytes: 0 },
|
|
86
|
+
};
|
|
87
|
+
if (state.branches.length)
|
|
88
|
+
repo.branches = state.branches;
|
|
89
|
+
if (state.tags.length)
|
|
90
|
+
repo.tags = state.tags;
|
|
91
|
+
// Per-branch upstreams, restricted to remotes the manifest carries so a
|
|
92
|
+
// restore can always recreate the tracking ref.
|
|
93
|
+
const remoteNames = new Set(state.remotes.map((r) => r.name));
|
|
94
|
+
const upstreams = {};
|
|
95
|
+
for (const [b, up] of Object.entries(state.branchUpstreams)) {
|
|
96
|
+
if (remoteNames.has(up.split("/")[0]))
|
|
97
|
+
upstreams[b] = up;
|
|
98
|
+
}
|
|
99
|
+
if (Object.keys(upstreams).length)
|
|
100
|
+
repo.branchUpstreams = upstreams;
|
|
101
|
+
// Remote-tracking tips for every upstream the manifest names.
|
|
102
|
+
const tips = {};
|
|
103
|
+
for (const up of new Set([...(state.head.upstream ? [state.head.upstream] : []), ...Object.values(upstreams)])) {
|
|
104
|
+
const tip = state.upstreamTips[up];
|
|
105
|
+
if (tip && remoteNames.has(up.split("/")[0]))
|
|
106
|
+
tips[up] = tip;
|
|
107
|
+
}
|
|
108
|
+
if (Object.keys(tips).length)
|
|
109
|
+
repo.upstreamTips = tips;
|
|
110
|
+
if (state.stashes.length)
|
|
111
|
+
repo.stashes = state.stashes;
|
|
112
|
+
if (input.ignoredIncludes.length)
|
|
113
|
+
repo.ignoredIncludes = input.ignoredIncludes;
|
|
114
|
+
repos.push(repo);
|
|
115
|
+
}
|
|
116
|
+
// Harness transcript.
|
|
117
|
+
const harness = { kind: input.harness.kind, chunks: [] };
|
|
118
|
+
if (input.harness.sessionId)
|
|
119
|
+
harness.sessionId = input.harness.sessionId;
|
|
120
|
+
if (input.harness.cwd)
|
|
121
|
+
harness.cwd = input.harness.cwd;
|
|
122
|
+
if (input.harness.kind !== "none" && input.harness.sessionId && input.harness.cwd) {
|
|
123
|
+
const loc = await locateHarness(input.harness.kind, input.harness.sessionId, input.harness.cwd);
|
|
124
|
+
if (loc) {
|
|
125
|
+
const hFile = path.join(tmp, "harness.tar");
|
|
126
|
+
const cap = await captureHarness(loc, hFile, compression);
|
|
127
|
+
if (cap)
|
|
128
|
+
harness.chunks = await addFileChunks(cap.file, sources, allChunks);
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
const bytesTotal = allChunks.reduce((n, c) => n + c.size, 0);
|
|
132
|
+
const manifest = {
|
|
133
|
+
v: MANIFEST_VERSION,
|
|
134
|
+
capsuleId: input.capsuleId,
|
|
135
|
+
generation,
|
|
136
|
+
parentGeneration: input.parentGeneration ?? 0,
|
|
137
|
+
createdAt: new Date().toISOString(),
|
|
138
|
+
machine: machineInfo(packageVersion),
|
|
139
|
+
root: { kind: input.rootKind, name: input.rootName },
|
|
140
|
+
repos,
|
|
141
|
+
excludes: [...DEFAULT_EXCLUDES],
|
|
142
|
+
harness,
|
|
143
|
+
totals: { chunks: allChunks.length, bytes: bytesTotal, dedupedBytes: dedupedBytes(allChunks) },
|
|
144
|
+
};
|
|
145
|
+
// The manifest is itself a chunk: write it, hash it, and negotiate it with
|
|
146
|
+
// the rest so commit can reference it by sha256.
|
|
147
|
+
const manifestBytes = Buffer.from(JSON.stringify(manifest));
|
|
148
|
+
const manifestSha256 = sha256(manifestBytes);
|
|
149
|
+
const manifestFile = path.join(tmp, "manifest.json");
|
|
150
|
+
await writeFile(manifestFile, manifestBytes);
|
|
151
|
+
const manifestRef = { sha256: manifestSha256, size: manifestBytes.length };
|
|
152
|
+
allChunks.push(manifestRef);
|
|
153
|
+
if (!sources.has(manifestSha256))
|
|
154
|
+
sources.set(manifestSha256, { file: manifestFile, index: 0, size: manifestBytes.length });
|
|
155
|
+
// Distinct chunks, negotiate in batches of ≤ 200.
|
|
156
|
+
const distinct = new Map();
|
|
157
|
+
for (const c of allChunks)
|
|
158
|
+
distinct.set(c.sha256, c);
|
|
159
|
+
const wanted = [...distinct.values()];
|
|
160
|
+
let uploaded = 0;
|
|
161
|
+
let uploadedBytes = 0;
|
|
162
|
+
for (let i = 0; i < wanted.length; i += NEGOTIATE_BATCH) {
|
|
163
|
+
const batch = wanted.slice(i, i + NEGOTIATE_BATCH);
|
|
164
|
+
const neg = await tapi.negotiate(input.capsuleId, batch.map((c) => ({ sha256: c.sha256, size: c.size })));
|
|
165
|
+
// A basis chunk the server no longer has cannot be re-sent by reference:
|
|
166
|
+
// rebuild those repos with a full bundle and push again (once).
|
|
167
|
+
const lost = neg.missing.filter((m) => !sources.has(m.sha256) && carried.has(m.sha256));
|
|
168
|
+
if (lost.length > 0) {
|
|
169
|
+
const repos = new Set(lost.map((m) => carried.get(m.sha256)));
|
|
170
|
+
if ([...repos].every((r) => forceFull.has(r))) {
|
|
171
|
+
throw new Error(`server is missing basis chunks for ${[...repos].join(", ")} even after a full re-bundle`);
|
|
172
|
+
}
|
|
173
|
+
await rm(tmp, { recursive: true, force: true });
|
|
174
|
+
return pushCapsule(input, new Set([...forceFull, ...repos]));
|
|
175
|
+
}
|
|
176
|
+
await uploadMissing(neg.missing, sources);
|
|
177
|
+
uploaded += neg.missing.length;
|
|
178
|
+
for (const m of neg.missing)
|
|
179
|
+
uploadedBytes += m.size ?? distinct.get(m.sha256)?.size ?? 0;
|
|
180
|
+
}
|
|
181
|
+
const committed = await tapi.commit(input.capsuleId, {
|
|
182
|
+
manifest,
|
|
183
|
+
manifestSha256,
|
|
184
|
+
committedBy: input.committedBy ?? detectCommitter(),
|
|
185
|
+
});
|
|
186
|
+
const logicalBytes = allChunks.reduce((n, c) => n + c.size, 0);
|
|
187
|
+
const reusedBytes = Math.max(0, logicalBytes - uploadedBytes);
|
|
188
|
+
return {
|
|
189
|
+
// The server's generation record is authoritative for the number.
|
|
190
|
+
generation: committed.generation?.generation ?? generation,
|
|
191
|
+
bytesTotal,
|
|
192
|
+
dedupedBytes: manifest.totals.dedupedBytes ?? 0,
|
|
193
|
+
chunkCount: distinct.size,
|
|
194
|
+
uploaded,
|
|
195
|
+
reused: distinct.size - uploaded,
|
|
196
|
+
uploadedBytes,
|
|
197
|
+
logicalBytes,
|
|
198
|
+
reusedBytes,
|
|
199
|
+
savingsRatio: logicalBytes > 0 ? reusedBytes / logicalBytes : 0,
|
|
200
|
+
};
|
|
201
|
+
}
|
|
202
|
+
finally {
|
|
203
|
+
await rm(tmp, { recursive: true, force: true });
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
async function addFileChunks(file, sources, all) {
|
|
207
|
+
const refs = await chunkFile(file);
|
|
208
|
+
refs.forEach((r, index) => {
|
|
209
|
+
all.push(r);
|
|
210
|
+
if (!sources.has(r.sha256))
|
|
211
|
+
sources.set(r.sha256, { file, index, size: r.size });
|
|
212
|
+
});
|
|
213
|
+
return refs;
|
|
214
|
+
}
|
|
215
|
+
async function uploadMissing(missing, sources) {
|
|
216
|
+
let cursor = 0;
|
|
217
|
+
const workers = Array.from({ length: Math.min(PUT_CONCURRENCY, missing.length) }, async () => {
|
|
218
|
+
for (;;) {
|
|
219
|
+
const i = cursor++;
|
|
220
|
+
if (i >= missing.length)
|
|
221
|
+
return;
|
|
222
|
+
const item = missing[i];
|
|
223
|
+
const src = sources.get(item.sha256);
|
|
224
|
+
if (!src)
|
|
225
|
+
throw new Error(`server asked for an unknown chunk ${item.sha256}`);
|
|
226
|
+
const body = await readChunk(src.file, src.index);
|
|
227
|
+
await putWithRetry(item.putUrl, body);
|
|
228
|
+
}
|
|
229
|
+
});
|
|
230
|
+
await Promise.all(workers);
|
|
231
|
+
}
|
|
232
|
+
async function putWithRetry(url, body, attempts = 4) {
|
|
233
|
+
let delay = 400;
|
|
234
|
+
for (let attempt = 1;; attempt++) {
|
|
235
|
+
const res = await fetch(url, { method: "PUT", body });
|
|
236
|
+
if (res.ok)
|
|
237
|
+
return;
|
|
238
|
+
if (attempt >= attempts || (res.status < 500 && res.status !== 429)) {
|
|
239
|
+
throw new Error(`chunk upload failed: HTTP ${res.status}`);
|
|
240
|
+
}
|
|
241
|
+
await sleep(delay);
|
|
242
|
+
delay *= 2;
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
/** The Ditto Code runner authenticates with a ditto_agent_ token and pins the harness session via env. */
|
|
246
|
+
export function detectCommitter() {
|
|
247
|
+
const key = process.env.DITTO_API_KEY ?? "";
|
|
248
|
+
if (key.startsWith("ditto_agent_") || process.env.TELEPORT_HARNESS_SESSION_ID)
|
|
249
|
+
return "runner";
|
|
250
|
+
return "cli";
|
|
251
|
+
}
|
|
252
|
+
function sleep(ms) {
|
|
253
|
+
return new Promise((r) => setTimeout(r, ms));
|
|
254
|
+
}
|
|
255
|
+
function bundleBytes(chunks) {
|
|
256
|
+
return chunks.reduce((n, c) => n + c.size, 0);
|
|
257
|
+
}
|
|
258
|
+
function safe(rel) {
|
|
259
|
+
return rel.replace(/[^A-Za-z0-9._-]/g, "_") || "root";
|
|
260
|
+
}
|
|
261
|
+
//# sourceMappingURL=push.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"push.js","sourceRoot":"","sources":["../../src/teleport/push.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { Manifest } from "./types.js";
|
|
2
|
+
export interface RestoreResult {
|
|
3
|
+
root: string;
|
|
4
|
+
repos: string[];
|
|
5
|
+
harnessSessionId: string | null;
|
|
6
|
+
harnessCwd: string | null;
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* Rebuilds a capsule from its manifest and the downloaded chunk files (keyed by
|
|
10
|
+
* sha256). Each repo is reconstructed from its bundle(s), branches and
|
|
11
|
+
* upstreams are restored, the dirty worktree is untarred over the checkout, and
|
|
12
|
+
* the harness transcript (if any) is placed under the restored cwd.
|
|
13
|
+
*/
|
|
14
|
+
export declare function restoreCapsule(manifest: Manifest, chunkPath: (sha256: string) => string, destRoot: string, opts?: {
|
|
15
|
+
restoreHarness?: boolean;
|
|
16
|
+
}): Promise<RestoreResult>;
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
import { mkdir, mkdtemp, rm, writeFile } from "node:fs/promises";
|
|
2
|
+
import os from "node:os";
|
|
3
|
+
import path from "node:path";
|
|
4
|
+
import { git, gitOrThrow, isGitRepo } from "./git.js";
|
|
5
|
+
import { restoreClaudeTranscript } from "./harness.js";
|
|
6
|
+
import { detectCompression, extractWorktree } from "./worktree.js";
|
|
7
|
+
/**
|
|
8
|
+
* Rebuilds a capsule from its manifest and the downloaded chunk files (keyed by
|
|
9
|
+
* sha256). Each repo is reconstructed from its bundle(s), branches and
|
|
10
|
+
* upstreams are restored, the dirty worktree is untarred over the checkout, and
|
|
11
|
+
* the harness transcript (if any) is placed under the restored cwd.
|
|
12
|
+
*/
|
|
13
|
+
export async function restoreCapsule(manifest, chunkPath, destRoot, opts = {}) {
|
|
14
|
+
await mkdir(destRoot, { recursive: true });
|
|
15
|
+
const tmp = await mkdtemp(path.join(os.tmpdir(), "teleport-restore-"));
|
|
16
|
+
try {
|
|
17
|
+
const repos = [];
|
|
18
|
+
for (const repo of manifest.repos) {
|
|
19
|
+
const repoDest = path.resolve(destRoot, repo.relPath);
|
|
20
|
+
await mkdir(repoDest, { recursive: true });
|
|
21
|
+
await restoreRepo(repo, chunkPath, repoDest, tmp);
|
|
22
|
+
repos.push(repo.relPath);
|
|
23
|
+
}
|
|
24
|
+
let harnessCwd = null;
|
|
25
|
+
if (opts.restoreHarness && manifest.harness.kind !== "none" && manifest.harness.chunks.length > 0) {
|
|
26
|
+
const tar = path.join(tmp, "harness.tar");
|
|
27
|
+
await concatChunks(manifest.harness.chunks.map((c) => c.sha256), chunkPath, tar);
|
|
28
|
+
const originalCwd = manifest.harness.cwd ?? destRoot;
|
|
29
|
+
const targetCwd = manifest.root.kind === "repo" ? path.resolve(destRoot, manifest.repos[0]?.relPath ?? ".") : destRoot;
|
|
30
|
+
const compression = detectCompression(tar);
|
|
31
|
+
if (manifest.harness.kind === "claude-code" && manifest.harness.sessionId) {
|
|
32
|
+
await restoreClaudeTranscript(tar, compression, manifest.harness.sessionId, originalCwd, targetCwd);
|
|
33
|
+
}
|
|
34
|
+
else {
|
|
35
|
+
// Codex keys transcripts on absolute cwd inside a shared home; extract as-is.
|
|
36
|
+
extractWorktree(tar, os.homedir(), compression);
|
|
37
|
+
}
|
|
38
|
+
harnessCwd = targetCwd;
|
|
39
|
+
}
|
|
40
|
+
return { root: destRoot, repos, harnessSessionId: manifest.harness.sessionId ?? null, harnessCwd };
|
|
41
|
+
}
|
|
42
|
+
finally {
|
|
43
|
+
await rm(tmp, { recursive: true, force: true });
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
async function restoreRepo(repo, chunkPath, repoDest, tmp) {
|
|
47
|
+
const hasBundle = repo.packs.some((p) => p.chunks.length > 0);
|
|
48
|
+
if (hasBundle) {
|
|
49
|
+
// Reassemble every pack into one bare prerequisite repo, then clone from it
|
|
50
|
+
// (a fetch into a repo whose branch is checked out is refused by git).
|
|
51
|
+
const bundleDir = path.join(tmp, `bundles-${sanitize(repo.relPath)}`);
|
|
52
|
+
await mkdir(bundleDir, { recursive: true });
|
|
53
|
+
const scratch = path.join(tmp, `scratch-${sanitize(repo.relPath)}`);
|
|
54
|
+
gitOrThrow(["init", "--bare", scratch], tmp);
|
|
55
|
+
// Full packs first, then thin packs oldest basis → newest, so every
|
|
56
|
+
// bundle's prerequisites are present before it is fetched.
|
|
57
|
+
const ordered = [...repo.packs].sort((a, b) => {
|
|
58
|
+
if (a.kind !== b.kind)
|
|
59
|
+
return a.kind === "full" ? -1 : 1;
|
|
60
|
+
return (a.basisGeneration ?? 0) - (b.basisGeneration ?? 0);
|
|
61
|
+
});
|
|
62
|
+
for (let i = 0; i < ordered.length; i++) {
|
|
63
|
+
const bundleFile = path.join(bundleDir, `pack-${i}.bundle`);
|
|
64
|
+
await concatChunks(ordered[i].chunks.map((c) => c.sha256), chunkPath, bundleFile);
|
|
65
|
+
gitOrThrow(["fetch", "--tags", bundleFile, "+refs/*:refs/*"], scratch);
|
|
66
|
+
}
|
|
67
|
+
// Clone the bare repo into the destination: this copies every branch and
|
|
68
|
+
// tag with a real working tree, without a fetch-into-checked-out-branch.
|
|
69
|
+
gitOrThrow(["clone", scratch, repoDest], tmp);
|
|
70
|
+
// Local tracking branches for every branch the capsule carried, so a later
|
|
71
|
+
// checkout of any of them works offline.
|
|
72
|
+
for (const branch of repo.branches ?? []) {
|
|
73
|
+
if (git(["rev-parse", "--verify", `refs/heads/${branch}`], repoDest).ok)
|
|
74
|
+
continue;
|
|
75
|
+
git(["branch", "--no-track", branch, `refs/remotes/origin/${branch}`], repoDest);
|
|
76
|
+
}
|
|
77
|
+
git(["remote", "remove", "origin"], repoDest);
|
|
78
|
+
}
|
|
79
|
+
else if (!isGitRepo(repoDest)) {
|
|
80
|
+
gitOrThrow(["init", repoDest], tmp);
|
|
81
|
+
}
|
|
82
|
+
// Remotes.
|
|
83
|
+
for (const remote of repo.remotes) {
|
|
84
|
+
if (git(["remote", "get-url", remote.name], repoDest).ok) {
|
|
85
|
+
git(["remote", "set-url", remote.name, remote.url], repoDest);
|
|
86
|
+
}
|
|
87
|
+
else {
|
|
88
|
+
git(["remote", "add", remote.name, remote.url], repoDest);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
// Check out the recorded HEAD/branch and re-establish upstream tracking.
|
|
92
|
+
if (repo.head.branch && (repo.branches ?? []).includes(repo.head.branch)) {
|
|
93
|
+
gitOrThrow(["checkout", "-f", repo.head.branch], repoDest);
|
|
94
|
+
if (repo.head.upstream)
|
|
95
|
+
restoreUpstream(repoDest, repo, repo.head.branch, repo.head.upstream);
|
|
96
|
+
}
|
|
97
|
+
else if (repo.head.sha) {
|
|
98
|
+
gitOrThrow(["checkout", "-f", repo.head.sha], repoDest);
|
|
99
|
+
}
|
|
100
|
+
// Every other branch that tracked a remote gets its tracking ref back too.
|
|
101
|
+
for (const [branch, upstream] of Object.entries(repo.branchUpstreams ?? {})) {
|
|
102
|
+
if (branch === repo.head.branch && repo.head.upstream)
|
|
103
|
+
continue;
|
|
104
|
+
if (!git(["rev-parse", "--verify", `refs/heads/${branch}`], repoDest).ok)
|
|
105
|
+
continue;
|
|
106
|
+
restoreUpstream(repoDest, repo, branch, upstream);
|
|
107
|
+
}
|
|
108
|
+
// Dirty worktree over the checkout.
|
|
109
|
+
if (repo.worktree?.chunks?.length) {
|
|
110
|
+
const tar = path.join(tmp, `worktree-${sanitize(repo.relPath)}.tar`);
|
|
111
|
+
await concatChunks(repo.worktree.chunks.map((c) => c.sha256), chunkPath, tar);
|
|
112
|
+
extractWorktree(tar, repoDest);
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* Recreates `<remote>/<branch>` tracking without a network fetch. The clone we
|
|
117
|
+
* restore from has no remote-tracking refs (its origin was the scratch repo),
|
|
118
|
+
* so `branch --set-upstream-to` would fail; instead the tracking ref is
|
|
119
|
+
* pointed at the branch tip the capsule recorded, then the upstream is set.
|
|
120
|
+
* The tip is the last state this machine knew of the upstream, so ahead/behind
|
|
121
|
+
* reads 0 until the next fetch. Any failure here is a hard error: silently
|
|
122
|
+
* losing tracking is exactly the bug this guards against.
|
|
123
|
+
*/
|
|
124
|
+
function restoreUpstream(repoDest, repo, branch, upstream) {
|
|
125
|
+
const remote = repo.remotes.find((r) => upstream === r.name || upstream.startsWith(`${r.name}/`));
|
|
126
|
+
if (!remote) {
|
|
127
|
+
throw new Error(`cannot restore upstream ${upstream} for ${branch}: remote is not in the capsule (${repo.remotes.map((r) => r.name).join(", ") || "none"})`);
|
|
128
|
+
}
|
|
129
|
+
const remoteBranch = upstream.slice(remote.name.length + 1);
|
|
130
|
+
if (!remoteBranch)
|
|
131
|
+
throw new Error(`cannot restore upstream ${upstream}: no branch component`);
|
|
132
|
+
const tip = repo.upstreamTips?.[upstream];
|
|
133
|
+
if (tip) {
|
|
134
|
+
// The real remote-tracking sha captured at push time; its objects rode in
|
|
135
|
+
// the bundle, so ahead/behind is exactly what the source machine saw.
|
|
136
|
+
gitOrThrow(["update-ref", `refs/remotes/${remote.name}/${remoteBranch}`, tip], repoDest);
|
|
137
|
+
gitOrThrow(["branch", `--set-upstream-to=${upstream}`, branch], repoDest);
|
|
138
|
+
return;
|
|
139
|
+
}
|
|
140
|
+
// Older capsules carry no tip: configure the upstream but never fabricate the
|
|
141
|
+
// tracking ref — offload treats "configured, ref missing" as unknown.
|
|
142
|
+
gitOrThrow(["config", `branch.${branch}.remote`, remote.name], repoDest);
|
|
143
|
+
gitOrThrow(["config", `branch.${branch}.merge`, `refs/heads/${remoteBranch}`], repoDest);
|
|
144
|
+
}
|
|
145
|
+
async function concatChunks(shas, chunkPath, outFile) {
|
|
146
|
+
const { createWriteStream } = await import("node:fs");
|
|
147
|
+
const { readFile } = await import("node:fs/promises");
|
|
148
|
+
const ws = createWriteStream(outFile);
|
|
149
|
+
try {
|
|
150
|
+
for (const sha of shas) {
|
|
151
|
+
const buf = await readFile(chunkPath(sha));
|
|
152
|
+
await new Promise((resolve, reject) => ws.write(buf, (err) => (err ? reject(err) : resolve())));
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
finally {
|
|
156
|
+
await new Promise((resolve) => ws.end(resolve));
|
|
157
|
+
}
|
|
158
|
+
void writeFile; // keep import set stable if unused in future edits
|
|
159
|
+
}
|
|
160
|
+
function sanitize(rel) {
|
|
161
|
+
return rel.replace(/[^A-Za-z0-9._-]/g, "_") || "root";
|
|
162
|
+
}
|
|
163
|
+
//# sourceMappingURL=restore.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"restore.js","sourceRoot":"","sources":["../../src/teleport/restore.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,EAAE,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AACjE,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,GAAG,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC;AACtD,OAAO,EAAE,uBAAuB,EAAE,MAAM,cAAc,CAAC;AACvD,OAAO,EAAE,iBAAiB,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAUnE;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,cAAc,CAClC,QAAkB,EAClB,SAAqC,EACrC,QAAgB,EAChB,OAAqC,EAAE;IAEvC,MAAM,KAAK,CAAC,QAAQ,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAC3C,MAAM,GAAG,GAAG,MAAM,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,MAAM,EAAE,EAAE,mBAAmB,CAAC,CAAC,CAAC;IACvE,IAAI,CAAC;QACH,MAAM,KAAK,GAAa,EAAE,CAAC;QAC3B,KAAK,MAAM,IAAI,IAAI,QAAQ,CAAC,KAAK,EAAE,CAAC;YAClC,MAAM,QAAQ,GAAG,IAAI,CAAC,OAAO,CAAC,QAAQ,EAAE,IAAI,CAAC,OAAO,CAAC,CAAC;YACtD,MAAM,KAAK,CAAC,QAAQ,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;YAC3C,MAAM,WAAW,CAAC,IAAI,EAAE,SAAS,EAAE,QAAQ,EAAE,GAAG,CAAC,CAAC;YAClD,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QAC3B,CAAC;QACD,IAAI,UAAU,GAAkB,IAAI,CAAC;QACrC,IAAI,IAAI,CAAC,cAAc,IAAI,QAAQ,CAAC,OAAO,CAAC,IAAI,KAAK,MAAM,IAAI,QAAQ,CAAC,OAAO,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAClG,MAAM,GAAG,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,aAAa,CAAC,CAAC;YAC1C,MAAM,YAAY,CAAC,QAAQ,CAAC,OAAO,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,EAAE,SAAS,EAAE,GAAG,CAAC,CAAC;YACjF,MAAM,WAAW,GAAG,QAAQ,CAAC,OAAO,CAAC,GAAG,IAAI,QAAQ,CAAC;YACrD,MAAM,SAAS,GACb,QAAQ,CAAC,IAAI,CAAC,IAAI,KAAK,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,QAAQ,EAAE,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,OAAO,IAAI,GAAG,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC;YACvG,MAAM,WAAW,GAAG,iBAAiB,CAAC,GAAG,CAAC,CAAC;YAC3C,IAAI,QAAQ,CAAC,OAAO,CAAC,IAAI,KAAK,aAAa,IAAI,QAAQ,CAAC,OAAO,CAAC,SAAS,EAAE,CAAC;gBAC1E,MAAM,uBAAuB,CAAC,GAAG,EAAE,WAAW,EAAE,QAAQ,CAAC,OAAO,CAAC,SAAS,EAAE,WAAW,EAAE,SAAS,CAAC,CAAC;YACtG,CAAC;iBAAM,CAAC;gBACN,8EAA8E;gBAC9E,eAAe,CAAC,GAAG,EAAE,EAAE,CAAC,OAAO,EAAE,EAAE,WAAW,CAAC,CAAC;YAClD,CAAC;YACD,UAAU,GAAG,SAAS,CAAC;QACzB,CAAC;QACD,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,KAAK,EAAE,gBAAgB,EAAE,QAAQ,CAAC,OAAO,CAAC,SAAS,IAAI,IAAI,EAAE,UAAU,EAAE,CAAC;IACrG,CAAC;YAAS,CAAC;QACT,MAAM,EAAE,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;IAClD,CAAC;AACH,CAAC;AAED,KAAK,UAAU,WAAW,CACxB,IAAkB,EAClB,SAAqC,EACrC,QAAgB,EAChB,GAAW;IAEX,MAAM,SAAS,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;IAC9D,IAAI,SAAS,EAAE,CAAC;QACd,4EAA4E;QAC5E,uEAAuE;QACvE,MAAM,SAAS,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,WAAW,QAAQ,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;QACtE,MAAM,KAAK,CAAC,SAAS,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QAC5C,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,WAAW,QAAQ,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;QACpE,UAAU,CAAC,CAAC,MAAM,EAAE,QAAQ,EAAE,OAAO,CAAC,EAAE,GAAG,CAAC,CAAC;QAC7C,oEAAoE;QACpE,2DAA2D;QAC3D,MAAM,OAAO,GAAG,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE;YAC5C,IAAI,CAAC,CAAC,IAAI,KAAK,CAAC,CAAC,IAAI;gBAAE,OAAO,CAAC,CAAC,IAAI,KAAK,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;YACzD,OAAO,CAAC,CAAC,CAAC,eAAe,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,eAAe,IAAI,CAAC,CAAC,CAAC;QAC7D,CAAC,CAAC,CAAC;QACH,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;YACxC,MAAM,UAAU,GAAG,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,QAAQ,CAAC,SAAS,CAAC,CAAC;YAC5D,MAAM,YAAY,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,EAAE,SAAS,EAAE,UAAU,CAAC,CAAC;YAClF,UAAU,CAAC,CAAC,OAAO,EAAE,QAAQ,EAAE,UAAU,EAAE,gBAAgB,CAAC,EAAE,OAAO,CAAC,CAAC;QACzE,CAAC;QACD,yEAAyE;QACzE,yEAAyE;QACzE,UAAU,CAAC,CAAC,OAAO,EAAE,OAAO,EAAE,QAAQ,CAAC,EAAE,GAAG,CAAC,CAAC;QAC9C,2EAA2E;QAC3E,yCAAyC;QACzC,KAAK,MAAM,MAAM,IAAI,IAAI,CAAC,QAAQ,IAAI,EAAE,EAAE,CAAC;YACzC,IAAI,GAAG,CAAC,CAAC,WAAW,EAAE,UAAU,EAAE,cAAc,MAAM,EAAE,CAAC,EAAE,QAAQ,CAAC,CAAC,EAAE;gBAAE,SAAS;YAClF,GAAG,CAAC,CAAC,QAAQ,EAAE,YAAY,EAAE,MAAM,EAAE,uBAAuB,MAAM,EAAE,CAAC,EAAE,QAAQ,CAAC,CAAC;QACnF,CAAC;QACD,GAAG,CAAC,CAAC,QAAQ,EAAE,QAAQ,EAAE,QAAQ,CAAC,EAAE,QAAQ,CAAC,CAAC;IAChD,CAAC;SAAM,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,EAAE,CAAC;QAChC,UAAU,CAAC,CAAC,MAAM,EAAE,QAAQ,CAAC,EAAE,GAAG,CAAC,CAAC;IACtC,CAAC;IACD,WAAW;IACX,KAAK,MAAM,MAAM,IAAI,IAAI,CAAC,OAAO,EAAE,CAAC;QAClC,IAAI,GAAG,CAAC,CAAC,QAAQ,EAAE,SAAS,EAAE,MAAM,CAAC,IAAI,CAAC,EAAE,QAAQ,CAAC,CAAC,EAAE,EAAE,CAAC;YACzD,GAAG,CAAC,CAAC,QAAQ,EAAE,SAAS,EAAE,MAAM,CAAC,IAAI,EAAE,MAAM,CAAC,GAAG,CAAC,EAAE,QAAQ,CAAC,CAAC;QAChE,CAAC;aAAM,CAAC;YACN,GAAG,CAAC,CAAC,QAAQ,EAAE,KAAK,EAAE,MAAM,CAAC,IAAI,EAAE,MAAM,CAAC,GAAG,CAAC,EAAE,QAAQ,CAAC,CAAC;QAC5D,CAAC;IACH,CAAC;IACD,yEAAyE;IACzE,IAAI,IAAI,CAAC,IAAI,CAAC,MAAM,IAAI,CAAC,IAAI,CAAC,QAAQ,IAAI,EAAE,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC;QACzE,UAAU,CAAC,CAAC,UAAU,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,QAAQ,CAAC,CAAC;QAC3D,IAAI,IAAI,CAAC,IAAI,CAAC,QAAQ;YAAE,eAAe,CAAC,QAAQ,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;IAChG,CAAC;SAAM,IAAI,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC;QACzB,UAAU,CAAC,CAAC,UAAU,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,QAAQ,CAAC,CAAC;IAC1D,CAAC;IACD,2EAA2E;IAC3E,KAAK,MAAM,CAAC,MAAM,EAAE,QAAQ,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,eAAe,IAAI,EAAE,CAAC,EAAE,CAAC;QAC5E,IAAI,MAAM,KAAK,IAAI,CAAC,IAAI,CAAC,MAAM,IAAI,IAAI,CAAC,IAAI,CAAC,QAAQ;YAAE,SAAS;QAChE,IAAI,CAAC,GAAG,CAAC,CAAC,WAAW,EAAE,UAAU,EAAE,cAAc,MAAM,EAAE,CAAC,EAAE,QAAQ,CAAC,CAAC,EAAE;YAAE,SAAS;QACnF,eAAe,CAAC,QAAQ,EAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,CAAC,CAAC;IACpD,CAAC;IACD,oCAAoC;IACpC,IAAI,IAAI,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC;QAClC,MAAM,GAAG,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,YAAY,QAAQ,CAAC,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;QACrE,MAAM,YAAY,CAAC,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,EAAE,SAAS,EAAE,GAAG,CAAC,CAAC;QAC9E,eAAe,CAAC,GAAG,EAAE,QAAQ,CAAC,CAAC;IACjC,CAAC;AACH,CAAC;AAED;;;;;;;;GAQG;AACH,SAAS,eAAe,CAAC,QAAgB,EAAE,IAAkB,EAAE,MAAc,EAAE,QAAgB;IAC7F,MAAM,MAAM,GAAG,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,QAAQ,KAAK,CAAC,CAAC,IAAI,IAAI,QAAQ,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,IAAI,GAAG,CAAC,CAAC,CAAC;IAClG,IAAI,CAAC,MAAM,EAAE,CAAC;QACZ,MAAM,IAAI,KAAK,CAAC,2BAA2B,QAAQ,QAAQ,MAAM,mCAAmC,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,MAAM,GAAG,CAAC,CAAC;IAC/J,CAAC;IACD,MAAM,YAAY,GAAG,QAAQ,CAAC,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;IAC5D,IAAI,CAAC,YAAY;QAAE,MAAM,IAAI,KAAK,CAAC,2BAA2B,QAAQ,uBAAuB,CAAC,CAAC;IAC/F,MAAM,GAAG,GAAG,IAAI,CAAC,YAAY,EAAE,CAAC,QAAQ,CAAC,CAAC;IAC1C,IAAI,GAAG,EAAE,CAAC;QACR,0EAA0E;QAC1E,sEAAsE;QACtE,UAAU,CAAC,CAAC,YAAY,EAAE,gBAAgB,MAAM,CAAC,IAAI,IAAI,YAAY,EAAE,EAAE,GAAG,CAAC,EAAE,QAAQ,CAAC,CAAC;QACzF,UAAU,CAAC,CAAC,QAAQ,EAAE,qBAAqB,QAAQ,EAAE,EAAE,MAAM,CAAC,EAAE,QAAQ,CAAC,CAAC;QAC1E,OAAO;IACT,CAAC;IACD,8EAA8E;IAC9E,sEAAsE;IACtE,UAAU,CAAC,CAAC,QAAQ,EAAE,UAAU,MAAM,SAAS,EAAE,MAAM,CAAC,IAAI,CAAC,EAAE,QAAQ,CAAC,CAAC;IACzE,UAAU,CAAC,CAAC,QAAQ,EAAE,UAAU,MAAM,QAAQ,EAAE,cAAc,YAAY,EAAE,CAAC,EAAE,QAAQ,CAAC,CAAC;AAC3F,CAAC;AAED,KAAK,UAAU,YAAY,CACzB,IAAc,EACd,SAAqC,EACrC,OAAe;IAEf,MAAM,EAAE,iBAAiB,EAAE,GAAG,MAAM,MAAM,CAAC,SAAS,CAAC,CAAC;IACtD,MAAM,EAAE,QAAQ,EAAE,GAAG,MAAM,MAAM,CAAC,kBAAkB,CAAC,CAAC;IACtD,MAAM,EAAE,GAAG,iBAAiB,CAAC,OAAO,CAAC,CAAC;IACtC,IAAI,CAAC;QACH,KAAK,MAAM,GAAG,IAAI,IAAI,EAAE,CAAC;YACvB,MAAM,GAAG,GAAG,MAAM,QAAQ,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC;YAC3C,MAAM,IAAI,OAAO,CAAO,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,CAAC;QACxG,CAAC;IACH,CAAC;YAAS,CAAC;QACT,MAAM,IAAI,OAAO,CAAO,CAAC,OAAO,EAAE,EAAE,CAAC,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC;IACxD,CAAC;IACD,KAAK,SAAS,CAAC,CAAC,mDAAmD;AACrE,CAAC;AAED,SAAS,QAAQ,CAAC,GAAW;IAC3B,OAAO,GAAG,CAAC,OAAO,CAAC,kBAAkB,EAAE,GAAG,CAAC,IAAI,MAAM,CAAC;AACxD,CAAC"}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Bring-your-own buckets that capsules can mirror to, managed through the
|
|
3
|
+
* teleport API (`/api/v5/teleport/buckets`), which accepts the CLI's
|
|
4
|
+
* ditto_mcp_ key. Any S3-compatible endpoint works (AWS S3, R2, B2, MinIO,
|
|
5
|
+
* Hippius); `providerKind` is detected server-side from the endpoint.
|
|
6
|
+
*/
|
|
7
|
+
export interface StorageBucket {
|
|
8
|
+
id: string;
|
|
9
|
+
name?: string;
|
|
10
|
+
providerKind?: "s3" | "hippius";
|
|
11
|
+
bucket: string;
|
|
12
|
+
endpoint: string;
|
|
13
|
+
region: string;
|
|
14
|
+
enabled: boolean;
|
|
15
|
+
default: boolean;
|
|
16
|
+
teleportMirror?: boolean;
|
|
17
|
+
keyHint?: string;
|
|
18
|
+
credentialState?: string;
|
|
19
|
+
}
|
|
20
|
+
export interface AddBucketInput {
|
|
21
|
+
name?: string;
|
|
22
|
+
providerKind?: "s3" | "hippius";
|
|
23
|
+
accessKeyID: string;
|
|
24
|
+
secretAccessKey: string;
|
|
25
|
+
bucket: string;
|
|
26
|
+
endpoint: string;
|
|
27
|
+
region?: string;
|
|
28
|
+
enabled?: boolean;
|
|
29
|
+
default?: boolean;
|
|
30
|
+
teleportMirror?: boolean;
|
|
31
|
+
}
|
|
32
|
+
export interface UpdateBucketInput {
|
|
33
|
+
name?: string;
|
|
34
|
+
enabled?: boolean;
|
|
35
|
+
default?: boolean;
|
|
36
|
+
teleportMirror?: boolean;
|
|
37
|
+
}
|
|
38
|
+
export interface TestResult {
|
|
39
|
+
ok: boolean;
|
|
40
|
+
error?: string;
|
|
41
|
+
}
|
|
42
|
+
export declare function listBuckets(): Promise<StorageBucket[]>;
|
|
43
|
+
export declare function addBucket(input: AddBucketInput): Promise<StorageBucket>;
|
|
44
|
+
export declare function updateBucket(id: string, input: UpdateBucketInput): Promise<StorageBucket>;
|
|
45
|
+
export declare function removeBucket(id: string): Promise<void>;
|
|
46
|
+
/** Tests a stored bucket's credentials. */
|
|
47
|
+
export declare function testBucket(id: string): Promise<TestResult>;
|
|
48
|
+
/** Tests credentials before they are saved. */
|
|
49
|
+
export declare function testDraft(input: AddBucketInput): Promise<TestResult>;
|
|
50
|
+
/** Resolves a bucket by id or by its friendly name (or, failing that, the bucket name). */
|
|
51
|
+
export declare function resolveBucket(ref: string): Promise<StorageBucket>;
|
|
52
|
+
/** Human summary of where a bucket lives, for `storage list`. */
|
|
53
|
+
export declare function bucketEndpointLabel(b: StorageBucket): string;
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { apiBase, apiFetch } from "../api.js";
|
|
2
|
+
const BUCKETS = "/api/v5/teleport/buckets";
|
|
3
|
+
export async function listBuckets() {
|
|
4
|
+
const res = await apiFetch(BUCKETS);
|
|
5
|
+
return res.buckets ?? [];
|
|
6
|
+
}
|
|
7
|
+
export async function addBucket(input) {
|
|
8
|
+
return apiFetch(BUCKETS, { method: "POST", body: input });
|
|
9
|
+
}
|
|
10
|
+
export async function updateBucket(id, input) {
|
|
11
|
+
return apiFetch(`${BUCKETS}/${encodeURIComponent(id)}`, { method: "PATCH", body: input });
|
|
12
|
+
}
|
|
13
|
+
export async function removeBucket(id) {
|
|
14
|
+
await apiFetch(`${BUCKETS}/${encodeURIComponent(id)}`, { method: "DELETE" });
|
|
15
|
+
}
|
|
16
|
+
/** Tests a stored bucket's credentials. */
|
|
17
|
+
export async function testBucket(id) {
|
|
18
|
+
return apiFetch(`${BUCKETS}/test`, { method: "POST", body: { bucketId: id } });
|
|
19
|
+
}
|
|
20
|
+
/** Tests credentials before they are saved. */
|
|
21
|
+
export async function testDraft(input) {
|
|
22
|
+
return apiFetch(`${BUCKETS}/test`, { method: "POST", body: { settings: input } });
|
|
23
|
+
}
|
|
24
|
+
/** Resolves a bucket by id or by its friendly name (or, failing that, the bucket name). */
|
|
25
|
+
export async function resolveBucket(ref) {
|
|
26
|
+
const buckets = await listBuckets();
|
|
27
|
+
const hit = buckets.find((b) => b.id === ref) ??
|
|
28
|
+
buckets.find((b) => b.name === ref) ??
|
|
29
|
+
buckets.find((b) => b.bucket === ref);
|
|
30
|
+
if (!hit)
|
|
31
|
+
throw new Error(`no bucket named "${ref}"; see \`heyditto storage list\``);
|
|
32
|
+
return hit;
|
|
33
|
+
}
|
|
34
|
+
/** Human summary of where a bucket lives, for `storage list`. */
|
|
35
|
+
export function bucketEndpointLabel(b) {
|
|
36
|
+
try {
|
|
37
|
+
return new URL(b.endpoint).host;
|
|
38
|
+
}
|
|
39
|
+
catch {
|
|
40
|
+
return b.endpoint || apiBase();
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
//# sourceMappingURL=storage.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"storage.js","sourceRoot":"","sources":["../../src/teleport/storage.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAC;AA+C9C,MAAM,OAAO,GAAG,0BAA0B,CAAC;AAE3C,MAAM,CAAC,KAAK,UAAU,WAAW;IAC/B,MAAM,GAAG,GAAG,MAAM,QAAQ,CAAgC,OAAO,CAAC,CAAC;IACnE,OAAO,GAAG,CAAC,OAAO,IAAI,EAAE,CAAC;AAC3B,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,SAAS,CAAC,KAAqB;IACnD,OAAO,QAAQ,CAAgB,OAAO,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;AAC3E,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,YAAY,CAAC,EAAU,EAAE,KAAwB;IACrE,OAAO,QAAQ,CAAgB,GAAG,OAAO,IAAI,kBAAkB,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,MAAM,EAAE,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;AAC3G,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,YAAY,CAAC,EAAU;IAC3C,MAAM,QAAQ,CAAO,GAAG,OAAO,IAAI,kBAAkB,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC,CAAC;AACrF,CAAC;AAED,2CAA2C;AAC3C,MAAM,CAAC,KAAK,UAAU,UAAU,CAAC,EAAU;IACzC,OAAO,QAAQ,CAAa,GAAG,OAAO,OAAO,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,EAAE,QAAQ,EAAE,EAAE,EAAE,EAAE,CAAC,CAAC;AAC7F,CAAC;AAED,+CAA+C;AAC/C,MAAM,CAAC,KAAK,UAAU,SAAS,CAAC,KAAqB;IACnD,OAAO,QAAQ,CAAa,GAAG,OAAO,OAAO,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,EAAE,QAAQ,EAAE,KAAK,EAAE,EAAE,CAAC,CAAC;AAChG,CAAC;AAED,2FAA2F;AAC3F,MAAM,CAAC,KAAK,UAAU,aAAa,CAAC,GAAW;IAC7C,MAAM,OAAO,GAAG,MAAM,WAAW,EAAE,CAAC;IACpC,MAAM,GAAG,GACP,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,GAAG,CAAC;QACjC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,GAAG,CAAC;QACnC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,KAAK,GAAG,CAAC,CAAC;IACxC,IAAI,CAAC,GAAG;QAAE,MAAM,IAAI,KAAK,CAAC,oBAAoB,GAAG,kCAAkC,CAAC,CAAC;IACrF,OAAO,GAAG,CAAC;AACb,CAAC;AAED,iEAAiE;AACjE,MAAM,UAAU,mBAAmB,CAAC,CAAgB;IAClD,IAAI,CAAC;QACH,OAAO,IAAI,GAAG,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC;IAClC,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,CAAC,CAAC,QAAQ,IAAI,OAAO,EAAE,CAAC;IACjC,CAAC;AACH,CAAC"}
|