@anna-ai/cli 0.1.47 → 0.1.51

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.
Files changed (63) hide show
  1. package/dist/{account-BBMYzSH7.js → account-C-IeQNNr.js} +1 -1
  2. package/dist/{agent-DAOr_aiE.js → agent-CX2VzG7e.js} +1 -1
  3. package/dist/{apps-DlVsVHQ5.js → apps-BRBufSyX.js} +8 -41
  4. package/dist/{apps-BQcbrExH.js → apps-CTIiH6a_.js} +4 -2
  5. package/dist/apps-cut-35wivw1Z.js +19 -0
  6. package/dist/{apps-cut-DWodD5oE.js → apps-cut-L7T8b5RS.js} +20 -22
  7. package/dist/{apps-destructive-BVjpOxNF.js → apps-destructive-DcG3T1Mx.js} +2 -2
  8. package/dist/{apps-discard-5z0K4-o3.js → apps-discard-CKA_m7Yw.js} +7 -7
  9. package/dist/apps-grants-B5MpWhSO.js +70 -0
  10. package/dist/apps-publish-CGfzN7tI.js +92 -0
  11. package/dist/apps-publish-CUJILNOt.js +22 -0
  12. package/dist/apps-push-BcYNGSYx.js +20 -0
  13. package/dist/{app-bundle-upload-CzWR9jxI.js → apps-push-d1C0eePp.js} +144 -69
  14. package/dist/{apps-release-DuaJI9iX.js → apps-release-DxRHjEYJ.js} +2 -2
  15. package/dist/{apps-rename-slug-BGpitGyw.js → apps-rename-slug-4_5lsDwg.js} +2 -2
  16. package/dist/{apps-status-BVIL6DYc.js → apps-status-hMrRz356.js} +6 -1
  17. package/dist/{apps-submit-review-BmPjkoe9.js → apps-submit-review-CxoKgexX.js} +9 -3
  18. package/dist/{apps-sync-meta-87RK1Usm.js → apps-sync-meta-BwN8g6TO.js} +3 -3
  19. package/dist/{apps-versions-DfapYfW-.js → apps-versions-gfG_sBFv.js} +10 -5
  20. package/dist/{bridge-sFHqOOat.js → bridge-Bo8eu3-d.js} +1 -1
  21. package/dist/bridge-nv-le8ff.js +3 -0
  22. package/dist/cli.js +45 -45
  23. package/dist/{dev-ClCDRplP.js → dev-BB1oS-1o.js} +4 -4
  24. package/dist/dev-DAkNdyJ-.js +4 -0
  25. package/dist/{dev-app-cache-B3Wa5t6X.js → dev-app-cache-CScRa7c3.js} +9 -2
  26. package/dist/{doctor-CHnkbamq.js → doctor-qFe9sXxR.js} +1 -1
  27. package/dist/{executa-destructive-Du7RGJgn.js → executa-destructive-C06mgvfJ.js} +1 -1
  28. package/dist/{executa-dev-CSzM-Oha.js → executa-dev-ONm9di1H.js} +8 -8
  29. package/dist/executa-install-DKMwLq-V.js +7 -0
  30. package/dist/{executa-install-CM4x4doq.js → executa-install-n1oRAoYJ.js} +1 -1
  31. package/dist/{executa-publish-BKnsUoZq.js → executa-publish-BuakG1RK.js} +38 -11
  32. package/dist/{executa-publish-6awuH4Ma.js → executa-publish-CVlMaHIY.js} +3 -3
  33. package/dist/{executa-upload-binaries-FWM2yXfB.js → executa-upload-binaries-BVWs6MFF.js} +2 -2
  34. package/dist/{executa-upload-binaries-DwWQ18Dq.js → executa-upload-binaries-D0JWYOtK.js} +1 -1
  35. package/dist/{listing-meta-35VYXW5a.js → listing-meta-rIni8tjd.js} +1 -1
  36. package/dist/{manifest-B_DjigtQ.js → manifest-BCHiC184.js} +49 -3
  37. package/dist/{publish-Bg4TkKoX.js → publish-CIaosgo4.js} +13 -10
  38. package/dist/{server-Dr_htFv8.js → server-poDjwty-.js} +1 -1
  39. package/dist/{storage-aii8EyPC.js → storage-CZ4c4ibf.js} +1 -1
  40. package/dist/{working-orchestration-CKXkvXVC.js → working-orchestration-BRU7FV-b.js} +9 -5
  41. package/package.json +3 -3
  42. package/dist/apps-grants-baOFOxnO.js +0 -34
  43. package/dist/apps-publish-Ck-2BEu3.js +0 -272
  44. package/dist/apps-publish-CrpTz6WY.js +0 -17
  45. package/dist/apps-push-CNOI2ruX.js +0 -152
  46. package/dist/bridge-BP28T06H.js +0 -3
  47. package/dist/dev-C251jRh2.js +0 -4
  48. package/dist/executa-install-V5fSZRdO.js +0 -7
  49. /package/dist/{confirm-ChZAVrZe.js → confirm-DplLyBSG.js} +0 -0
  50. /package/dist/{dev-account-CfVdGa9j.js → dev-account-IrYL4u4F.js} +0 -0
  51. /package/dist/{executa-init-DKy7DMSD.js → executa-init-BM0HR-K7.js} +0 -0
  52. /package/dist/{executa-reads-BYKUADoL.js → executa-reads-BJpmB-B1.js} +0 -0
  53. /package/dist/{executa-register-CmqKsoAU.js → executa-register-CDKG3L5c.js} +0 -0
  54. /package/dist/{executa-trusted-publisher-BGqz6hMt.js → executa-trusted-publisher-n9IbAO5D.js} +0 -0
  55. /package/dist/{fixture-BF1Z0Rry.js → fixture-CizypXzX.js} +0 -0
  56. /package/dist/{host_upload-CW_2Fxg6.js → host_upload-BvzJZKAO.js} +0 -0
  57. /package/dist/{image-B4UrufYH.js → image-C61zRJC8.js} +0 -0
  58. /package/dist/{login-DbETuUxy.js → login-BleVDjXE.js} +0 -0
  59. /package/dist/{logout-BzIEf-HU.js → logout-BO4brBaY.js} +0 -0
  60. /package/dist/{runner-Dq3cluPM.js → runner-aq0n-pdr.js} +0 -0
  61. /package/dist/{sampling-BpJcd6BC.js → sampling-BQwF3O-4.js} +0 -0
  62. /package/dist/{token-TgBQumgy.js → token-DeAZLyVz.js} +0 -0
  63. /package/dist/{whoami-Bn38ns8r.js → whoami-rvVc_nQ9.js} +0 -0
@@ -1,8 +1,13 @@
1
- import { finalizeBundle, finalizeWorkingBundle, getBundle, initBundle, initWorkingBundle, uploadBundleFile, uploadWorkingBundleFile } from "./apps-DlVsVHQ5.js";
1
+ import { finalizeWorkingBundle, getApp, getWorkingDraft, initWorkingBundle, uploadWorkingBundleFile, upsertWorkingDraft } from "./apps-BRBufSyX.js";
2
2
  import { CliError } from "./client-sMzq2PWG.js";
3
- import { canonicalize } from "./executa-publish-BKnsUoZq.js";
4
- import { join, relative, sep } from "node:path";
3
+ import { resolveClient, withErrorHandling } from "./_lifecycle-shared-_9BzQ9Y2.js";
4
+ import { loadAppManifest } from "./manifest-BCHiC184.js";
5
+ import { bumpVersion, bundleHash, canonicalize, manifestHash, rewriteVersion } from "./executa-publish-BuakG1RK.js";
6
+ import { installLocalBundledShims, resolveAppIdentity, resolveBundledExecutas } from "./working-orchestration-BRU7FV-b.js";
7
+ import { syncAppListingMeta } from "./listing-meta-rIni8tjd.js";
8
+ import { join, relative, resolve, sep } from "node:path";
5
9
  import { readFileSync, readdirSync, statSync } from "node:fs";
10
+ import { bold, cyan, dim, green, yellow } from "kleur/colors";
6
11
  import { createHash } from "node:crypto";
7
12
 
8
13
  //#region src/publish/app-bundle-upload.ts
@@ -84,71 +89,6 @@ function manifestFingerprint(files) {
84
89
  };
85
90
  return createHash("sha256").update(canonicalize(obj)).digest("hex");
86
91
  }
87
- /**
88
- * Upload + finalize the UI bundle for one app version. Returns
89
- * `{ status: "skipped" }` when the version's bundle is already finalized
90
- * with identical content.
91
- */
92
- async function uploadAppBundle(params) {
93
- const { client, appId, versionId, bundleDir, entryPath, bundleFormat = "static-spa", externalOrigins = [], log } = params;
94
- const files = collectFiles(bundleDir);
95
- if (files.length === 0) throw new CliError(`bundle directory is empty: ${bundleDir}`, 4);
96
- if (files.length > MAX_FILES) throw new CliError(`too many bundle files (${files.length} > ${MAX_FILES})`, 4);
97
- const totalBytes = files.reduce((s, f) => s + f.entry.byte_size, 0);
98
- if (totalBytes > MAX_TOTAL_BYTES) throw totalSizeError(totalBytes);
99
- const tooBig = files.find((f) => f.entry.byte_size > MAX_FILE_BYTES);
100
- if (tooBig) throw fileSizeError(tooBig.relativePath, tooBig.entry.byte_size);
101
- if (!files.some((f) => f.relativePath === entryPath)) throw new CliError(`manifest entry "${entryPath}" not found in bundle dir ${bundleDir}`, 4);
102
- const fingerprint = manifestFingerprint(files);
103
- const existing = await getBundle(client, appId, versionId);
104
- if (existing && existing.status === "bundle_ready") {
105
- if (existing.sha256_manifest === fingerprint) {
106
- log?.(` bundle unchanged (${files.length} files, sha ${fingerprint.slice(0, 12)}…) — skipped`);
107
- return {
108
- status: "skipped",
109
- reason: "unchanged",
110
- detail: existing
111
- };
112
- }
113
- throw new CliError("version already has a finalized bundle with different content; bump the app version (e.g. --bump patch) to upload a new bundle", 4);
114
- }
115
- log?.(` uploading UI bundle: ${files.length} files, ${(totalBytes / 1024).toFixed(1)} KB`);
116
- const fileMap = {};
117
- for (const f of files) fileMap[f.relativePath] = f.entry;
118
- const initResp = await initBundle(client, appId, versionId, {
119
- file_map: fileMap,
120
- total_size_bytes: totalBytes,
121
- file_count: files.length,
122
- bundle_format: bundleFormat,
123
- entry_path: entryPath,
124
- external_origins: externalOrigins
125
- });
126
- const proxyByPath = new Map(initResp.files.map((p) => [p.relative_path, p.proxy_upload_url]));
127
- const skipSet = new Set(initResp.files.filter((p) => p.skip_upload).map((p) => p.relative_path));
128
- const toUpload = files.filter((f) => !skipSet.has(f.relativePath));
129
- if (skipSet.size > 0) log?.(` ♻ ${skipSet.size}/${files.length} files unchanged on server — skipped (dedup)`);
130
- const queue = [...toUpload];
131
- const uploadOne = async () => {
132
- for (;;) {
133
- const f = queue.shift();
134
- if (!f) return;
135
- const proxyUrl = proxyByPath.get(f.relativePath);
136
- if (!proxyUrl) throw new CliError(`server did not return an upload URL for ${f.relativePath}`, 6);
137
- const ab = f.bytes.buffer.slice(f.bytes.byteOffset, f.bytes.byteOffset + f.bytes.byteLength);
138
- const blob = new Blob([ab], { type: f.entry.content_type });
139
- await uploadBundleFile(client, appId, versionId, f.relativePath, blob);
140
- }
141
- };
142
- await Promise.all(Array.from({ length: Math.min(UPLOAD_PARALLEL, toUpload.length) }, uploadOne));
143
- const detail = await finalizeBundle(client, appId, versionId, false);
144
- log?.(` ✓ bundle finalized (${detail.file_count} files, status=${detail.status})`);
145
- return {
146
- status: "uploaded",
147
- detail,
148
- fileCount: files.length,
149
- totalBytes
150
- };
151
- }
152
92
  /** True when `path` is an existing directory. */
153
93
  function isExistingDir(path) {
154
94
  try {
@@ -223,4 +163,139 @@ async function uploadWorkingBundle(params) {
223
163
  }
224
164
 
225
165
  //#endregion
226
- export { isExistingDir, uploadAppBundle, uploadWorkingBundle };
166
+ //#region src/commands/apps-push.ts
167
+ async function runAppsPush(opts) {
168
+ return withErrorHandling(async () => {
169
+ const cwd = resolve(opts.cwd ?? process.cwd());
170
+ const manifest = loadAppManifest(cwd, opts.manifest);
171
+ const silent = opts.json === true || opts.quiet === true;
172
+ const { client, host, source } = resolveClient({ account: opts.account });
173
+ if (!silent) console.log(dim(`using PAT from ${source} (host=${host})`));
174
+ if (opts.bump) {
175
+ const next = bumpVersion(manifest.version, opts.bump);
176
+ if (!silent) console.log(yellow(`↑ bumping manifest.version: ${manifest.version} → ${next}`));
177
+ if (!opts.noWrite && !opts.dryRun) rewriteVersion(manifest.metadataPath, manifest.metadataRaw, next);
178
+ manifest.version = next;
179
+ manifest.metadataRaw.version = next;
180
+ }
181
+ const { publishManifestRaw, resolved } = await resolveBundledExecutas({
182
+ manifest,
183
+ cwd,
184
+ host,
185
+ executaId: opts.executaId,
186
+ skipExecutaPublish: opts.skipExecutaPublish,
187
+ noBundledExecutas: opts.noBundledExecutas,
188
+ dryRun: opts.dryRun,
189
+ freeze: false,
190
+ lockSource: "working",
191
+ profile: opts.profile,
192
+ account: opts.account,
193
+ json: silent
194
+ });
195
+ let installedShims = [];
196
+ if (!opts.dryRun && !opts.noInstallLocal && Object.keys(resolved).length > 0) installedShims = await installLocalBundledShims({
197
+ manifest,
198
+ cwd,
199
+ resolved,
200
+ profile: opts.profile,
201
+ json: silent
202
+ });
203
+ const identity = await resolveAppIdentity({
204
+ client,
205
+ cwd,
206
+ host,
207
+ manifest,
208
+ dryRun: opts.dryRun,
209
+ json: silent
210
+ });
211
+ if (!identity) return 0;
212
+ const { appId, serverSlug, firstPublish } = identity;
213
+ const hashInput = {
214
+ version: manifest.version,
215
+ manifest: publishManifestRaw
216
+ };
217
+ const bundleEntry = publishManifestRaw.ui?.bundle?.entry;
218
+ const bundleDir = resolve(cwd, opts.bundleDir ?? "bundle");
219
+ const hasBundle = !!bundleEntry && !opts.noBundle && isExistingDir(bundleDir);
220
+ const hash = hasBundle ? bundleHash(hashInput, bundleDir) : manifestHash(hashInput);
221
+ if (opts.dryRun) {
222
+ if (!silent) console.log(yellow(`[dry-run] app_id=${appId} slug=${serverSlug}; would PUT /working (content_hash=${hash.slice(0, 12)}…)` + (hasBundle ? ` + stage working bundle from ${bundleDir}` : "")));
223
+ return 0;
224
+ }
225
+ let resp;
226
+ try {
227
+ resp = await upsertWorkingDraft(client, appId, {
228
+ manifest: publishManifestRaw,
229
+ changelog: manifest.changelog,
230
+ content_hash: hash
231
+ }, opts.ifMatch);
232
+ } catch (e) {
233
+ if (e instanceof CliError && e.status === 409) throw new CliError(`working draft was modified concurrently (If-Match=${opts.ifMatch} is stale); re-run \`apps push\` without --if-match for last-writer-wins, or fetch the current revision with \`apps status\``, 4);
234
+ throw e;
235
+ }
236
+ let bundleResult = null;
237
+ if (hasBundle) {
238
+ const uiBundle = publishManifestRaw.ui.bundle;
239
+ const skipStage = resp.unchanged && resp.bundle_status === "ready";
240
+ if (!skipStage) bundleResult = await uploadWorkingBundle({
241
+ client,
242
+ appId,
243
+ bundleDir,
244
+ entryPath: uiBundle.entry,
245
+ bundleFormat: uiBundle.format,
246
+ externalOrigins: Array.isArray(uiBundle.external_origins) ? uiBundle.external_origins : [],
247
+ log: silent ? void 0 : (m) => console.log(dim(m))
248
+ });
249
+ }
250
+ try {
251
+ await syncAppListingMeta(client, appId, manifest, { cwd });
252
+ } catch (err) {
253
+ if (!silent) console.log(yellow(`! listing metadata sync skipped: ${err.message}`));
254
+ }
255
+ const finalApp = await getApp(client, appId);
256
+ const draft = await getWorkingDraft(client, appId);
257
+ const captured = {
258
+ app_id: appId,
259
+ slug: serverSlug,
260
+ host,
261
+ version: manifest.version,
262
+ revision: resp.revision,
263
+ content_hash: resp.content_hash,
264
+ unchanged: resp.unchanged,
265
+ bundle_status: resp.bundle_status,
266
+ first_publish: firstPublish,
267
+ status: finalApp.status,
268
+ dirty_vs_latest_cut: draft?.dirty_vs_latest_cut ?? null,
269
+ installed_shims: installedShims,
270
+ bundle: bundleResult ? {
271
+ status: bundleResult.status,
272
+ file_count: bundleResult.fileCount,
273
+ total_size_bytes: bundleResult.totalBytes,
274
+ bundle_status: bundleResult.bundleStatus
275
+ } : null
276
+ };
277
+ opts.capture?.(captured);
278
+ if (opts.json) {
279
+ if (!opts.quiet) console.log(JSON.stringify(captured, null, 2));
280
+ return 0;
281
+ }
282
+ if (opts.quiet) return 0;
283
+ if (resp.unchanged) console.log(green(`✓ apps/${serverSlug}: working draft unchanged (rev ${resp.revision})`));
284
+ else console.log(green(`✓ apps/${serverSlug}: working draft updated (rev ${resp.revision})`));
285
+ if (firstPublish) console.log(dim(` first push — wrote .anna/app.json`));
286
+ if (bundleResult) if (bundleResult.status === "skipped") console.log(dim(` working bundle unchanged — skipped`));
287
+ else console.log(green(` ✓ working bundle: ${bundleResult.fileCount} files, ${(bundleResult.totalBytes / 1024).toFixed(1)} KB → ${bundleResult.bundleStatus}`));
288
+ console.log(bold(cyan(`status: ${finalApp.status}`)));
289
+ if (draft?.dirty_vs_latest_cut) console.log(dim(` (uncommitted changes vs latest cut version)`));
290
+ if (installedShims.length > 0) {
291
+ for (const s of installedShims) console.log(green(` ✓ installed local dev shim: `) + cyan(s.tool_id));
292
+ console.log(dim(`→ click `) + cyan(`Rediscover Local`) + dim(` in the Agent's Plugin Details to load `) + (installedShims.length === 1 ? dim("it") : dim("them")));
293
+ }
294
+ console.log(dim(`→ install & test the draft (reserved `) + cyan(`0.0.0-draft`) + dim(`) from the Developer Console`));
295
+ console.log(dim(`→ run `) + cyan(`anna-app apps cut ${manifest.version}`) + dim(` to snapshot an immutable version`));
296
+ return 0;
297
+ });
298
+ }
299
+
300
+ //#endregion
301
+ export { runAppsPush };
@@ -1,5 +1,5 @@
1
1
  import { canonicalHost } from "./credentials-BTv2IfUZ.js";
2
- import { findAppBySlug, getApp, getBundle, listVersions, publishVersion } from "./apps-DlVsVHQ5.js";
2
+ import { findAppBySlug, getApp, getBundle, listVersions, publishVersion } from "./apps-BRBufSyX.js";
3
3
  import { CliError } from "./client-sMzq2PWG.js";
4
4
  import { resolveClient, withErrorHandling } from "./_lifecycle-shared-_9BzQ9Y2.js";
5
5
  import { readAppIdentity } from "./app-cache-Cr3tKbux.js";
@@ -59,7 +59,7 @@ async function runAppsRelease(opts) {
59
59
  if (!target) {
60
60
  if (opts.allowCreate) {
61
61
  if (!opts.json) console.log(yellow(`version ${opts.version} not found remotely; running 'apps publish' first (--allow-create)…`));
62
- const { runAppsPublish } = await import("./apps-publish-CrpTz6WY.js");
62
+ const { runAppsPublish } = await import("./apps-publish-CUJILNOt.js");
63
63
  const code = await runAppsPublish({
64
64
  cwd: opts.cwd,
65
65
  account: opts.account,
@@ -1,8 +1,8 @@
1
1
  import "./credentials-BTv2IfUZ.js";
2
- import { findAppBySlug, patchApp } from "./apps-DlVsVHQ5.js";
2
+ import { findAppBySlug, patchApp } from "./apps-BRBufSyX.js";
3
3
  import { CliError } from "./client-sMzq2PWG.js";
4
4
  import { reportError, resolveClient } from "./_lifecycle-shared-_9BzQ9Y2.js";
5
- import { loadAppManifest } from "./manifest-B_DjigtQ.js";
5
+ import { loadAppManifest } from "./manifest-BCHiC184.js";
6
6
  import { readAppIdentity, writeAppIdentity } from "./app-cache-Cr3tKbux.js";
7
7
  import { writeFileSync } from "node:fs";
8
8
  import { bold, dim, green, red, yellow } from "kleur/colors";
@@ -1,5 +1,5 @@
1
1
  import "./credentials-BTv2IfUZ.js";
2
- import { findAppBySlug, getApp, listVersions } from "./apps-DlVsVHQ5.js";
2
+ import { findAppBySlug, getApp, listVersions } from "./apps-BRBufSyX.js";
3
3
  import { CliError } from "./client-sMzq2PWG.js";
4
4
  import { resolveClient, withErrorHandling } from "./_lifecycle-shared-_9BzQ9Y2.js";
5
5
  import { bold, cyan, dim, green, red, yellow } from "kleur/colors";
@@ -23,6 +23,7 @@ async function runAppsStatus(opts) {
23
23
  visibility: full.visibility ?? null,
24
24
  is_published: full.is_published ?? false,
25
25
  review_message: full.review_message ?? null,
26
+ review_candidate_version: full.review_candidate_version ?? null,
26
27
  latest_version: latest ? {
27
28
  id: latest.id,
28
29
  version: latest.version,
@@ -39,6 +40,10 @@ async function runAppsStatus(opts) {
39
40
  console.log(` ${dim("status :")} ${colorStatus(full.status)}` + (full.is_published ? " " + green("[published]") : ""));
40
41
  if (latest) console.log(` ${dim("latest :")} v${latest.version} (id=${latest.id}, published=${latest.published_at ?? "—"})`);
41
42
  else console.log(` ${dim("latest :")} ${dim("(no versions yet)")}`);
43
+ if (full.review_candidate_version) {
44
+ const isReleaseReview = (full.status || "").toUpperCase() === "PUBLISHED";
45
+ console.log(` ${dim("in review :")} ${yellow(`v${full.review_candidate_version}`)} ${dim(isReleaseReview ? "(release under review — awaiting admin approval)" : "(pinned at submit-review)")}`);
46
+ }
42
47
  if (full.review_message) console.log(` ${dim("reviewer :")} ${full.review_message}`);
43
48
  console.log(` ${dim("versions :")} ${versions.length} total`);
44
49
  return 0;
@@ -1,10 +1,10 @@
1
1
  import { canonicalHost } from "./credentials-BTv2IfUZ.js";
2
- import { findAppBySlug, getApp, submitForReview } from "./apps-DlVsVHQ5.js";
2
+ import { findAppBySlug, getApp, submitForReview } from "./apps-BRBufSyX.js";
3
3
  import { CliError } from "./client-sMzq2PWG.js";
4
4
  import { resolveClient, withErrorHandling } from "./_lifecycle-shared-_9BzQ9Y2.js";
5
5
  import { readAppIdentity } from "./app-cache-Cr3tKbux.js";
6
6
  import { resolve } from "node:path";
7
- import { bold, cyan, green } from "kleur/colors";
7
+ import { bold, cyan, dim, green } from "kleur/colors";
8
8
 
9
9
  //#region src/commands/apps-submit-review.ts
10
10
  async function runAppsSubmitReview(opts) {
@@ -26,17 +26,23 @@ async function runAppsSubmitReview(opts) {
26
26
  }
27
27
  const app = await submitForReview(client, appId);
28
28
  const finalApp = await getApp(client, appId);
29
+ const candidate = app.review_candidate_version ?? finalApp.review_candidate_version ?? null;
29
30
  if (opts.json) {
30
31
  console.log(JSON.stringify({
31
32
  host,
32
33
  app_id: appId,
33
34
  slug: serverSlug,
34
- status: finalApp.status
35
+ status: finalApp.status,
36
+ review_candidate_version: candidate
35
37
  }, null, 2));
36
38
  return 0;
37
39
  }
38
40
  console.log(green(`✓ apps/${serverSlug}: submitted for review`));
39
41
  console.log(bold(cyan(`status: ${app.status ?? finalApp.status}`)));
42
+ if (candidate) {
43
+ console.log(`under review: ${bold(`v${candidate}`)}`);
44
+ console.log(dim("versions cut after this point are NOT part of this review round — re-run `apps submit-review` to re-pin to the newest cut"));
45
+ }
40
46
  return 0;
41
47
  });
42
48
  }
@@ -1,10 +1,10 @@
1
1
  import { canonicalHost } from "./credentials-BTv2IfUZ.js";
2
- import { findAppBySlug, getApp } from "./apps-DlVsVHQ5.js";
2
+ import { findAppBySlug, getApp } from "./apps-BRBufSyX.js";
3
3
  import { CliError } from "./client-sMzq2PWG.js";
4
4
  import { resolveClient, withErrorHandling } from "./_lifecycle-shared-_9BzQ9Y2.js";
5
- import { loadAppManifest } from "./manifest-B_DjigtQ.js";
5
+ import { loadAppManifest } from "./manifest-BCHiC184.js";
6
6
  import { readAppIdentity } from "./app-cache-Cr3tKbux.js";
7
- import { syncAppListingMeta } from "./listing-meta-35VYXW5a.js";
7
+ import { syncAppListingMeta } from "./listing-meta-rIni8tjd.js";
8
8
  import { resolve } from "node:path";
9
9
  import { bold, cyan, dim, green } from "kleur/colors";
10
10
 
@@ -1,8 +1,8 @@
1
1
  import "./credentials-BTv2IfUZ.js";
2
- import { findAppBySlug, listVersions } from "./apps-DlVsVHQ5.js";
2
+ import { findAppBySlug, listVersions } from "./apps-BRBufSyX.js";
3
3
  import { CliError } from "./client-sMzq2PWG.js";
4
4
  import { resolveClient, withErrorHandling } from "./_lifecycle-shared-_9BzQ9Y2.js";
5
- import { bold, cyan, dim, green } from "kleur/colors";
5
+ import { bold, cyan, dim, green, red, yellow } from "kleur/colors";
6
6
 
7
7
  //#region src/commands/apps-versions.ts
8
8
  async function runAppsVersions(opts) {
@@ -16,12 +16,14 @@ async function runAppsVersions(opts) {
16
16
  host,
17
17
  app_id: app.id,
18
18
  slug: app.slug,
19
+ review_candidate_version: app.review_candidate_version ?? null,
19
20
  versions: versions.map((v) => ({
20
21
  id: v.id,
21
22
  version: v.version,
22
23
  is_latest: v.is_latest ?? false,
23
24
  published_at: v.published_at ?? null,
24
- created_at: v.created_at ?? null
25
+ created_at: v.created_at ?? null,
26
+ release_review_state: v.release_review_state ?? null
25
27
  }))
26
28
  }, null, 2));
27
29
  return 0;
@@ -32,9 +34,12 @@ async function runAppsVersions(opts) {
32
34
  return 0;
33
35
  }
34
36
  for (const v of versions) {
35
- const tag = v.is_latest ? green("[latest]") : dim(" ");
36
- console.log(` ${tag} v${v.version} ${dim(`(id=${v.id}, published=${v.published_at ?? ""})`)}`);
37
+ const inReview = v.version === app.review_candidate_version;
38
+ const tag = v.is_latest ? green("[latest]") : inReview ? yellow("[review]") : dim(" ");
39
+ const rereview = v.release_review_state === "pending" ? " " + yellow("(re-review pending)") : v.release_review_state === "rejected" ? " " + red("(re-review rejected)") : "";
40
+ console.log(` ${tag} v${v.version} ${dim(`(id=${v.id}, published=${v.published_at ?? "—"})`)}${rereview}`);
37
41
  }
42
+ if (app.status.toUpperCase() === "PUBLISHED" && !versions.some((v) => v.is_latest)) console.log(yellow(" ! app is PUBLISHED but no version is released — ") + yellow("new installs will fail; run `anna-app apps release <version>`"));
38
43
  return 0;
39
44
  });
40
45
  }
@@ -9,7 +9,7 @@ import { createInterface } from "node:readline";
9
9
  * `uvx <pkg>@<version>` so end users always run the dispatcher version
10
10
  * the CLI was tested against.
11
11
  */
12
- const PINNED_RUNTIME_VERSION = "0.2.0a21";
12
+ const PINNED_RUNTIME_VERSION = "0.2.0a23";
13
13
  /**
14
14
  * Throwable from a {@link RequestHandler} to send a structured JSON-RPC
15
15
  * error back to the python bridge with a stable string ``code`` (e.g.
@@ -0,0 +1,3 @@
1
+ import { BridgeRequestError, PINNED_RUNTIME_VERSION, PythonBridge } from "./bridge-Bo8eu3-d.js";
2
+
3
+ export { PINNED_RUNTIME_VERSION, PythonBridge };