pixelkiln 0.2.0 → 0.3.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/dist/index.cjs CHANGED
@@ -45,6 +45,8 @@ __export(index_exports, {
45
45
  PixelLabProvider: () => PixelLabProvider,
46
46
  StyleSchema: () => StyleSchema,
47
47
  UnsupportedCapabilityError: () => UnsupportedCapabilityError,
48
+ WorkspaceProjectSchema: () => WorkspaceProjectSchema,
49
+ WorkspaceSchema: () => WorkspaceSchema,
48
50
  adopt: () => adopt,
49
51
  applyTags: () => applyTags,
50
52
  auditStyle: () => auditStyle,
@@ -75,6 +77,8 @@ __export(index_exports, {
75
77
  loadClaims: () => loadClaims,
76
78
  loadLock: () => loadLock,
77
79
  loadManifest: () => loadManifest,
80
+ loadSiblingManifests: () => loadSiblingManifests,
81
+ loadWorkspace: () => loadWorkspace,
78
82
  lockKey: () => lockKey,
79
83
  matchOrphanStyle: () => matchOrphanStyle,
80
84
  measureBalanceChange: () => measureBalanceChange,
@@ -89,6 +93,7 @@ __export(index_exports, {
89
93
  packStyle: () => packStyle,
90
94
  paletteDistance: () => paletteDistance,
91
95
  parseLock: () => parseLock,
96
+ parseWorkspace: () => parseWorkspace,
92
97
  pngSize: () => pngSize,
93
98
  poll: () => poll,
94
99
  portableOutputPath: () => portableOutputPath,
@@ -102,6 +107,7 @@ __export(index_exports, {
102
107
  resolveEntryOutputs: () => resolveEntryOutputs,
103
108
  resolveOutputPath: () => resolveOutputPath,
104
109
  resolvePackInputs: () => resolvePackInputs,
110
+ resolveProject: () => resolveProject,
105
111
  resolveSpecEntryOutputs: () => resolveSpecEntryOutputs,
106
112
  resolveSpecOutputs: () => resolveSpecOutputs,
107
113
  resolveSpecs: () => resolveSpecs,
@@ -111,6 +117,7 @@ __export(index_exports, {
111
117
  runPicker: () => runPicker,
112
118
  runSalvage: () => runSalvage,
113
119
  saveLock: () => saveLock,
120
+ saveWorkspace: () => saveWorkspace,
114
121
  scanAssets: () => scanAssets,
115
122
  selectEntryOutput: () => selectEntryOutput,
116
123
  sha256: () => sha256,
@@ -126,11 +133,15 @@ __export(index_exports, {
126
133
  tileFeatureOutputCount: () => tileFeatureOutputCount,
127
134
  tileVariationCount: () => tileVariationCount,
128
135
  tilesCost: () => tilesCost,
136
+ toPortablePath: () => toPortablePath,
129
137
  totalSpend: () => totalSpend,
130
138
  upsert: () => upsert,
131
139
  validateCostEstimate: () => validateCostEstimate,
140
+ validateWorkspace: () => validateWorkspace,
132
141
  verifyArtifactBundle: () => verifyArtifactBundle,
133
142
  withArtifactManifest: () => withArtifactManifest,
143
+ workspaceClaims: () => workspaceClaims,
144
+ workspaceStatus: () => workspaceStatus,
134
145
  writeArtifactBundle: () => writeArtifactBundle,
135
146
  writeManagedArtifactBundle: () => writeManagedArtifactBundle
136
147
  });
@@ -547,11 +558,11 @@ var PixelLabClient = class {
547
558
  * common than the failure mode of retrying (a duplicate object), and a
548
559
  * duplicate is visible and free to delete whereas a silent gap is neither.
549
560
  */
550
- async request(path15, init, attempt = 0) {
561
+ async request(path17, init, attempt = 0) {
551
562
  const auth = this.apiKey.startsWith("Bearer ") ? this.apiKey : `Bearer ${this.apiKey}`;
552
563
  let res;
553
564
  try {
554
- res = await fetch(`${BASE}${path15}`, {
565
+ res = await fetch(`${BASE}${path17}`, {
555
566
  ...init,
556
567
  signal: init?.signal ?? AbortSignal.timeout(this.timeoutMs),
557
568
  headers: {
@@ -563,24 +574,24 @@ var PixelLabClient = class {
563
574
  } catch (err) {
564
575
  if (attempt < MAX_RETRIES) {
565
576
  await sleep(backoffMs(attempt));
566
- return this.request(path15, init, attempt + 1);
577
+ return this.request(path17, init, attempt + 1);
567
578
  }
568
579
  throw err;
569
580
  }
570
581
  if (!res.ok && shouldRetry(res.status) && attempt < MAX_RETRIES) {
571
582
  const waitMs = retryAfterMs(res.headers.get("retry-after")) ?? backoffMs(attempt);
572
583
  await sleep(waitMs);
573
- return this.request(path15, init, attempt + 1);
584
+ return this.request(path17, init, attempt + 1);
574
585
  }
575
586
  const text = await res.text();
576
587
  if (!res.ok) {
577
- throw new PixelLabError(`${init?.method ?? "GET"} ${path15} \u2192 ${res.status}`, res.status, text);
588
+ throw new PixelLabError(`${init?.method ?? "GET"} ${path17} \u2192 ${res.status}`, res.status, text);
578
589
  }
579
590
  if (!text) return {};
580
591
  try {
581
592
  return JSON.parse(text);
582
593
  } catch {
583
- throw new Error(`${init?.method ?? "GET"} ${path15} returned invalid JSON`);
594
+ throw new Error(`${init?.method ?? "GET"} ${path17} returned invalid JSON`);
584
595
  }
585
596
  }
586
597
  async balance() {
@@ -1598,8 +1609,8 @@ var import_promises = require("fs/promises");
1598
1609
  function sha256(data) {
1599
1610
  return (0, import_node_crypto3.createHash)("sha256").update(data).digest("hex");
1600
1611
  }
1601
- async function sha256File(path15) {
1602
- return sha256(await (0, import_promises.readFile)(path15));
1612
+ async function sha256File(path17) {
1613
+ return sha256(await (0, import_promises.readFile)(path17));
1603
1614
  }
1604
1615
  function specHash(spec, styleImageHashes) {
1605
1616
  return sha256(
@@ -2843,10 +2854,10 @@ function isSha256Hash(value) {
2843
2854
  function parseCache(value) {
2844
2855
  return HashCacheSchema.parse(value);
2845
2856
  }
2846
- async function loadCache(path15) {
2847
- if (!(0, import_node_fs6.existsSync)(path15)) return { version: 1, hashes: {} };
2857
+ async function loadCache(path17) {
2858
+ if (!(0, import_node_fs6.existsSync)(path17)) return { version: 1, hashes: {} };
2848
2859
  try {
2849
- const parsed = HashCacheSchema.safeParse(JSON.parse(await (0, import_promises6.readFile)(path15, "utf8")));
2860
+ const parsed = HashCacheSchema.safeParse(JSON.parse(await (0, import_promises6.readFile)(path17, "utf8")));
2850
2861
  if (!parsed.success) return { version: 1, hashes: {} };
2851
2862
  return {
2852
2863
  version: 1,
@@ -2858,18 +2869,18 @@ async function loadCache(path15) {
2858
2869
  return { version: 1, hashes: {} };
2859
2870
  }
2860
2871
  }
2861
- async function saveCache(path15, cache) {
2872
+ async function saveCache(path17, cache) {
2862
2873
  const sorted = {};
2863
2874
  for (const key of Object.keys(cache.hashes).sort()) {
2864
2875
  const hash = cache.hashes[key];
2865
2876
  if (!isSha256Hash(hash)) throw new Error(`Refusing to cache invalid SHA-256 for ${key}`);
2866
2877
  sorted[key] = hash;
2867
2878
  }
2868
- await (0, import_promises6.mkdir)(import_node_path8.default.dirname(import_node_path8.default.resolve(path15)), { recursive: true });
2869
- const tmp = `${path15}.${process.pid}.${Math.random().toString(36).slice(2)}.tmp`;
2879
+ await (0, import_promises6.mkdir)(import_node_path8.default.dirname(import_node_path8.default.resolve(path17)), { recursive: true });
2880
+ const tmp = `${path17}.${process.pid}.${Math.random().toString(36).slice(2)}.tmp`;
2870
2881
  try {
2871
2882
  await (0, import_promises6.writeFile)(tmp, JSON.stringify({ version: 1, hashes: sorted }, null, 2) + "\n");
2872
- await (0, import_promises6.rename)(tmp, path15);
2883
+ await (0, import_promises6.rename)(tmp, path17);
2873
2884
  } finally {
2874
2885
  await (0, import_promises6.rm)(tmp, { force: true });
2875
2886
  }
@@ -4602,6 +4613,7 @@ function mode(values) {
4602
4613
  // src/pipeline/salvage.ts
4603
4614
  var import_promises12 = require("fs/promises");
4604
4615
  var import_node_fs13 = require("fs");
4616
+ var import_node_path15 = __toESM(require("path"), 1);
4605
4617
  async function loadClaims(lockPaths) {
4606
4618
  const claimed = /* @__PURE__ */ new Set();
4607
4619
  for (const p of lockPaths) {
@@ -4654,6 +4666,26 @@ function matchOrphanStyle(prompt, manifest) {
4654
4666
  if (styleIds.length <= 1) return styleIds[0] ?? null;
4655
4667
  return matchStyleByPattern(prompt, manifest);
4656
4668
  }
4669
+ async function loadSiblingManifests(ownManifestPath, workspaceManifestPaths, claimPaths) {
4670
+ const own = import_node_path15.default.resolve(ownManifestPath);
4671
+ const siblingManifestPaths = [
4672
+ .../* @__PURE__ */ new Set([
4673
+ ...workspaceManifestPaths,
4674
+ ...claimPaths.map((c) => import_node_path15.default.join(import_node_path15.default.dirname(import_node_path15.default.resolve(c)), "pixelkiln.manifest.json"))
4675
+ ])
4676
+ ];
4677
+ const siblings = [];
4678
+ for (const siblingManifestPath of siblingManifestPaths) {
4679
+ if (import_node_path15.default.resolve(siblingManifestPath) === own) continue;
4680
+ if (!(0, import_node_fs13.existsSync)(siblingManifestPath)) continue;
4681
+ try {
4682
+ const { manifest } = await loadManifest(siblingManifestPath);
4683
+ siblings.push({ label: import_node_path15.default.basename(import_node_path15.default.dirname(siblingManifestPath)), manifest });
4684
+ } catch {
4685
+ }
4686
+ }
4687
+ return siblings;
4688
+ }
4657
4689
  function groupOrphansByStyle(orphans, manifest, siblings = []) {
4658
4690
  const matched = /* @__PURE__ */ new Map();
4659
4691
  const elsewhere = /* @__PURE__ */ new Map();
@@ -4765,7 +4797,7 @@ async function applyTags(provider, decisions, existing, opts = {}) {
4765
4797
 
4766
4798
  // src/pick/salvage-server.ts
4767
4799
  var import_promises13 = require("fs/promises");
4768
- var import_node_path15 = __toESM(require("path"), 1);
4800
+ var import_node_path16 = __toESM(require("path"), 1);
4769
4801
 
4770
4802
  // src/pick/salvage-sheet.ts
4771
4803
  var escapeHtml2 = (s) => s.replace(/[&<>"']/g, (c) => ({ "&": "&amp;", "<": "&lt;", ">": "&gt;", '"': "&quot;", "'": "&#39;" })[c]);
@@ -4930,7 +4962,7 @@ async function runSalvage(provider, orphans, ctx, opts = {}) {
4930
4962
  });
4931
4963
  const html = renderSalvageSheet(orphans, {
4932
4964
  styleId: ctx.styleId,
4933
- importDir: import_node_path15.default.relative(process.cwd(), ctx.importDir) || "."
4965
+ importDir: import_node_path16.default.relative(process.cwd(), ctx.importDir) || "."
4934
4966
  });
4935
4967
  const byId = new Map(orphans.map((o) => [o.id, o]));
4936
4968
  const existingTags = new Map(orphans.map((o) => [o.id, o.tags]));
@@ -4959,9 +4991,9 @@ async function runSalvage(provider, orphans, ctx, opts = {}) {
4959
4991
  if (!buf.subarray(0, 8).equals(PNG_SIGNATURE3)) throw new Error("not a PNG");
4960
4992
  decodePng(buf);
4961
4993
  const assetId = idFromPrompt(orphan.prompt, taken);
4962
- const rel = import_node_path15.default.join("_salvaged", `${assetId}.png`);
4963
- const outFile = import_node_path15.default.resolve(ctx.importDir, rel);
4964
- await (0, import_promises13.mkdir)(import_node_path15.default.dirname(outFile), { recursive: true });
4994
+ const rel = import_node_path16.default.join("_salvaged", `${assetId}.png`);
4995
+ const outFile = import_node_path16.default.resolve(ctx.importDir, rel);
4996
+ await (0, import_promises13.mkdir)(import_node_path16.default.dirname(outFile), { recursive: true });
4965
4997
  await (0, import_promises13.writeFile)(outFile, buf);
4966
4998
  ctx.manifest.assets[assetId] = {
4967
4999
  prompt: orphan.prompt,
@@ -4988,7 +5020,7 @@ async function runSalvage(provider, orphans, ctx, opts = {}) {
4988
5020
  error: null,
4989
5021
  sourceUrl: orphan.previewUrl,
4990
5022
  outputs: [{
4991
- path: portableOutputPath(outFile, import_node_path15.default.dirname(ctx.manifestPath)),
5023
+ path: portableOutputPath(outFile, import_node_path16.default.dirname(ctx.manifestPath)),
4992
5024
  sha256: sha256(buf)
4993
5025
  }],
4994
5026
  submittedAt: orphan.createdAt,
@@ -5020,6 +5052,233 @@ async function runSalvage(provider, orphans, ctx, opts = {}) {
5020
5052
  }
5021
5053
  });
5022
5054
  }
5055
+
5056
+ // src/workspace.ts
5057
+ var import_promises14 = require("fs/promises");
5058
+ var import_node_fs14 = require("fs");
5059
+ var import_node_path17 = __toESM(require("path"), 1);
5060
+ var import_zod4 = require("zod");
5061
+ var WorkspaceProjectSchema = import_zod4.z.object({
5062
+ id: import_zod4.z.string().min(1),
5063
+ /** Manifest path, relative to the catalog file's own directory. */
5064
+ manifest: import_zod4.z.string().min(1),
5065
+ /** Lockfile path, relative to the catalog file's own directory. */
5066
+ lock: import_zod4.z.string().min(1),
5067
+ provider: import_zod4.z.string().min(1).default("pixellab"),
5068
+ /** Free-form label for a shared account, e.g. distinguishing sandboxes. */
5069
+ account: import_zod4.z.string().optional()
5070
+ }).strict();
5071
+ var WorkspaceSchema = import_zod4.z.object({
5072
+ version: import_zod4.z.literal(1),
5073
+ projects: import_zod4.z.array(WorkspaceProjectSchema).default([])
5074
+ }).strict();
5075
+ function parseWorkspace(raw) {
5076
+ const parsed = WorkspaceSchema.safeParse(raw);
5077
+ if (parsed.success) return parsed.data;
5078
+ throw new Error(
5079
+ `Workspace catalog is not valid v1:
5080
+ ${parsed.error.issues.slice(0, 5).map((i) => ` ${i.path.join(".")}: ${i.message}`).join("\n")}`
5081
+ );
5082
+ }
5083
+ async function loadWorkspace(workspacePath) {
5084
+ if (!(0, import_node_fs14.existsSync)(workspacePath)) return { version: 1, projects: [] };
5085
+ let raw;
5086
+ try {
5087
+ raw = JSON.parse(await (0, import_promises14.readFile)(workspacePath, "utf8"));
5088
+ } catch (err) {
5089
+ throw new Error(
5090
+ `Workspace catalog at ${workspacePath} is malformed:
5091
+ ${err instanceof Error ? err.message : String(err)}`
5092
+ );
5093
+ }
5094
+ return parseWorkspace(raw);
5095
+ }
5096
+ async function saveWorkspace(workspacePath, ws) {
5097
+ const sorted = {
5098
+ version: 1,
5099
+ projects: [...ws.projects].sort((a, b) => a.id.localeCompare(b.id))
5100
+ };
5101
+ await (0, import_promises14.mkdir)(import_node_path17.default.dirname(import_node_path17.default.resolve(workspacePath)), { recursive: true });
5102
+ const tmp = `${workspacePath}.${process.pid}.${Math.random().toString(36).slice(2)}.tmp`;
5103
+ try {
5104
+ await (0, import_promises14.writeFile)(tmp, JSON.stringify(sorted, null, 2) + "\n");
5105
+ await (0, import_promises14.rename)(tmp, workspacePath);
5106
+ } finally {
5107
+ await (0, import_promises14.rm)(tmp, { force: true });
5108
+ }
5109
+ }
5110
+ function toPortablePath(dir, absolute) {
5111
+ return import_node_path17.default.relative(dir, absolute).split(import_node_path17.default.sep).join("/");
5112
+ }
5113
+ function resolveProject(dir, project) {
5114
+ return {
5115
+ manifestPath: import_node_path17.default.resolve(dir, project.manifest.split("/").join(import_node_path17.default.sep)),
5116
+ lockPath: import_node_path17.default.resolve(dir, project.lock.split("/").join(import_node_path17.default.sep))
5117
+ };
5118
+ }
5119
+ function validateWorkspace(ws, dir) {
5120
+ const diagnostics = [];
5121
+ const idCounts = /* @__PURE__ */ new Map();
5122
+ const lockOwners = /* @__PURE__ */ new Map();
5123
+ const manifestOwners = /* @__PURE__ */ new Map();
5124
+ for (const project of ws.projects) {
5125
+ idCounts.set(project.id, (idCounts.get(project.id) ?? 0) + 1);
5126
+ const { manifestPath, lockPath } = resolveProject(dir, project);
5127
+ lockOwners.set(lockPath, [...lockOwners.get(lockPath) ?? [], project.id]);
5128
+ manifestOwners.set(manifestPath, [...manifestOwners.get(manifestPath) ?? [], project.id]);
5129
+ if (import_node_path17.default.isAbsolute(project.manifest) || import_node_path17.default.isAbsolute(project.lock)) {
5130
+ diagnostics.push({
5131
+ id: "absolute-path",
5132
+ level: "warning",
5133
+ message: `project "${project.id}" stores an absolute path \u2014 the catalog will not resolve correctly if this tree is cloned or moved elsewhere`
5134
+ });
5135
+ }
5136
+ if (!(0, import_node_fs14.existsSync)(manifestPath)) {
5137
+ diagnostics.push({
5138
+ id: "missing-manifest",
5139
+ level: "error",
5140
+ message: `project "${project.id}" manifest not found: ${manifestPath}`
5141
+ });
5142
+ }
5143
+ if (!(0, import_node_fs14.existsSync)(lockPath)) {
5144
+ diagnostics.push({
5145
+ id: "missing-lock",
5146
+ level: "error",
5147
+ message: `project "${project.id}" lockfile not found: ${lockPath}`
5148
+ });
5149
+ }
5150
+ }
5151
+ for (const [id, count] of idCounts) {
5152
+ if (count > 1) {
5153
+ diagnostics.push({
5154
+ id: "duplicate-id",
5155
+ level: "error",
5156
+ message: `project id "${id}" is registered ${count} times`
5157
+ });
5158
+ }
5159
+ }
5160
+ for (const [lockPath, ids] of lockOwners) {
5161
+ if (ids.length > 1) {
5162
+ diagnostics.push({
5163
+ id: "duplicate-lock",
5164
+ level: "error",
5165
+ message: `${ids.join(", ")} all register the same lockfile: ${lockPath}`
5166
+ });
5167
+ }
5168
+ }
5169
+ for (const [manifestPath, ids] of manifestOwners) {
5170
+ if (ids.length > 1) {
5171
+ diagnostics.push({
5172
+ id: "duplicate-manifest",
5173
+ level: "warning",
5174
+ message: `${ids.join(", ")} share manifest ${manifestPath} \u2014 expected only when they are variant lockfiles beside one manifest`
5175
+ });
5176
+ }
5177
+ }
5178
+ const providers = new Set(ws.projects.map((p) => p.provider));
5179
+ if (providers.size > 1) {
5180
+ diagnostics.push({
5181
+ id: "mixed-provider",
5182
+ level: "warning",
5183
+ message: `registered projects use different providers: ${[...providers].sort().join(", ")} \u2014 spend totals are kept separate per unit, but confirm this is intentional`
5184
+ });
5185
+ }
5186
+ return diagnostics;
5187
+ }
5188
+
5189
+ // src/pipeline/workspace.ts
5190
+ async function workspaceClaims(ws, dir) {
5191
+ const lockPaths = [];
5192
+ const byProject = {};
5193
+ const claimed = /* @__PURE__ */ new Set();
5194
+ for (const project of ws.projects) {
5195
+ const { lockPath } = resolveProject(dir, project);
5196
+ lockPaths.push(lockPath);
5197
+ let projectClaims;
5198
+ try {
5199
+ projectClaims = await loadClaims([lockPath]);
5200
+ } catch (err) {
5201
+ throw new Error(
5202
+ `Project "${project.id}" lockfile is unreadable: ${err instanceof Error ? err.message : String(err)}`
5203
+ );
5204
+ }
5205
+ byProject[project.id] = projectClaims.size;
5206
+ for (const id of projectClaims) claimed.add(id);
5207
+ }
5208
+ return { claimed, byProject, lockPaths };
5209
+ }
5210
+ function emptyStateCounts() {
5211
+ return {
5212
+ ok: 0,
5213
+ missing: 0,
5214
+ untracked: 0,
5215
+ stale: 0,
5216
+ orphaned: 0,
5217
+ "in-flight": 0,
5218
+ recoverable: 0,
5219
+ failed: 0
5220
+ };
5221
+ }
5222
+ async function workspaceStatus(ws, dir) {
5223
+ const diagnostics = validateWorkspace(ws, dir);
5224
+ const provider = PixelLabProvider.forOffline();
5225
+ const projects = [];
5226
+ const totalsByState = emptyStateCounts();
5227
+ const totalsSpend = { generations: 0, usd: 0, free: 0 };
5228
+ for (const project of ws.projects) {
5229
+ const { manifestPath, lockPath } = resolveProject(dir, project);
5230
+ const base = {
5231
+ id: project.id,
5232
+ provider: project.provider,
5233
+ account: project.account ?? null,
5234
+ manifest: manifestPath,
5235
+ lock: lockPath
5236
+ };
5237
+ try {
5238
+ const loaded = await loadManifest(manifestPath);
5239
+ const specs = await resolveSpecs(loaded, { provider });
5240
+ const lock = await loadLock(lockPath);
5241
+ normalizeLockOutputPaths(lock, specs);
5242
+ const plan = await buildPlan(specs, lock);
5243
+ const byState = summarize(plan);
5244
+ const spend = spendByUnit(lock);
5245
+ for (const state of Object.keys(byState)) {
5246
+ totalsByState[state] += byState[state];
5247
+ }
5248
+ for (const unit of Object.keys(spend)) {
5249
+ totalsSpend[unit] += spend[unit];
5250
+ }
5251
+ projects.push({
5252
+ ...base,
5253
+ entries: Object.keys(lock.entries).length,
5254
+ byState,
5255
+ spendByUnit: spend,
5256
+ error: null
5257
+ });
5258
+ } catch (err) {
5259
+ projects.push({
5260
+ ...base,
5261
+ entries: 0,
5262
+ byState: emptyStateCounts(),
5263
+ spendByUnit: { generations: 0, usd: 0, free: 0 },
5264
+ error: err instanceof Error ? err.message : String(err)
5265
+ });
5266
+ }
5267
+ }
5268
+ let claims = 0;
5269
+ try {
5270
+ claims = (await workspaceClaims(ws, dir)).claimed.size;
5271
+ } catch {
5272
+ }
5273
+ return {
5274
+ version: 1,
5275
+ safe: !diagnostics.some((d) => d.level === "error") && projects.every((p) => !p.error),
5276
+ dir,
5277
+ projects,
5278
+ totals: { byState: totalsByState, spendByUnit: totalsSpend, claims },
5279
+ diagnostics
5280
+ };
5281
+ }
5023
5282
  // Annotate the CommonJS export names for ESM import in node:
5024
5283
  0 && (module.exports = {
5025
5284
  AssetSchema,
@@ -5037,6 +5296,8 @@ async function runSalvage(provider, orphans, ctx, opts = {}) {
5037
5296
  PixelLabProvider,
5038
5297
  StyleSchema,
5039
5298
  UnsupportedCapabilityError,
5299
+ WorkspaceProjectSchema,
5300
+ WorkspaceSchema,
5040
5301
  adopt,
5041
5302
  applyTags,
5042
5303
  auditStyle,
@@ -5067,6 +5328,8 @@ async function runSalvage(provider, orphans, ctx, opts = {}) {
5067
5328
  loadClaims,
5068
5329
  loadLock,
5069
5330
  loadManifest,
5331
+ loadSiblingManifests,
5332
+ loadWorkspace,
5070
5333
  lockKey,
5071
5334
  matchOrphanStyle,
5072
5335
  measureBalanceChange,
@@ -5081,6 +5344,7 @@ async function runSalvage(provider, orphans, ctx, opts = {}) {
5081
5344
  packStyle,
5082
5345
  paletteDistance,
5083
5346
  parseLock,
5347
+ parseWorkspace,
5084
5348
  pngSize,
5085
5349
  poll,
5086
5350
  portableOutputPath,
@@ -5094,6 +5358,7 @@ async function runSalvage(provider, orphans, ctx, opts = {}) {
5094
5358
  resolveEntryOutputs,
5095
5359
  resolveOutputPath,
5096
5360
  resolvePackInputs,
5361
+ resolveProject,
5097
5362
  resolveSpecEntryOutputs,
5098
5363
  resolveSpecOutputs,
5099
5364
  resolveSpecs,
@@ -5103,6 +5368,7 @@ async function runSalvage(provider, orphans, ctx, opts = {}) {
5103
5368
  runPicker,
5104
5369
  runSalvage,
5105
5370
  saveLock,
5371
+ saveWorkspace,
5106
5372
  scanAssets,
5107
5373
  selectEntryOutput,
5108
5374
  sha256,
@@ -5118,11 +5384,15 @@ async function runSalvage(provider, orphans, ctx, opts = {}) {
5118
5384
  tileFeatureOutputCount,
5119
5385
  tileVariationCount,
5120
5386
  tilesCost,
5387
+ toPortablePath,
5121
5388
  totalSpend,
5122
5389
  upsert,
5123
5390
  validateCostEstimate,
5391
+ validateWorkspace,
5124
5392
  verifyArtifactBundle,
5125
5393
  withArtifactManifest,
5394
+ workspaceClaims,
5395
+ workspaceStatus,
5126
5396
  writeArtifactBundle,
5127
5397
  writeManagedArtifactBundle
5128
5398
  });