@anna-ai/cli 0.1.49 → 0.1.52

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-CPnwqXeh.js → account-C-IeQNNr.js} +1 -1
  2. package/dist/{agent-DAOr_aiE.js → agent-CX2VzG7e.js} +1 -1
  3. package/dist/{apps-HbfURK6y.js → apps-BRBufSyX.js} +1 -41
  4. package/dist/{apps-CzqMRLbS.js → apps-CTIiH6a_.js} +1 -1
  5. package/dist/{apps-cut-BhTJwILv.js → apps-cut-BLtUBokD.js} +20 -22
  6. package/dist/apps-cut-eOVb1-0y.js +19 -0
  7. package/dist/{apps-destructive-PlaU93EX.js → apps-destructive-DcG3T1Mx.js} +2 -2
  8. package/dist/{apps-discard-CFi-GzpU.js → apps-discard-7ERq2pmS.js} +7 -7
  9. package/dist/{apps-grants-DqaX8UTy.js → apps-grants-DVoSb6-r.js} +7 -2
  10. package/dist/apps-publish-AdXryRYo.js +22 -0
  11. package/dist/apps-publish-BzaoSyFn.js +92 -0
  12. package/dist/{app-bundle-upload-Ca0r-kPy.js → apps-push-DZ1LHDJW.js} +144 -69
  13. package/dist/apps-push-WBfD0JyE.js +20 -0
  14. package/dist/{apps-release-DGQv6DDl.js → apps-release-DAV-DB_Q.js} +2 -2
  15. package/dist/{apps-rename-slug-CCEU_7JJ.js → apps-rename-slug-4_5lsDwg.js} +2 -2
  16. package/dist/{apps-status-C4Cxc2DF.js → apps-status-hMrRz356.js} +1 -1
  17. package/dist/{apps-submit-review--hZFZRJ3.js → apps-submit-review-CxoKgexX.js} +1 -1
  18. package/dist/{apps-sync-meta-DnFwFNl5.js → apps-sync-meta-BwN8g6TO.js} +3 -3
  19. package/dist/{apps-versions-C7NzG5Dk.js → apps-versions-gfG_sBFv.js} +1 -1
  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 +180 -55
  23. package/dist/dev-CQIZHt7u.js +4 -0
  24. package/dist/{dev-Bfv3WQC0.js → dev-uagVfV9Y.js} +7 -5
  25. package/dist/{doctor-CHnkbamq.js → doctor-qFe9sXxR.js} +1 -1
  26. package/dist/{executa-destructive-Du7RGJgn.js → executa-destructive-C06mgvfJ.js} +1 -1
  27. package/dist/{executa-dev-DYO87dzg.js → executa-dev-BeYhrj-n.js} +8 -8
  28. package/dist/executa-install-Dnerah9u.js +7 -0
  29. package/dist/{executa-install-DAposiBw.js → executa-install-u0nXcyy7.js} +1 -1
  30. package/dist/{executa-publish-BKnsUoZq.js → executa-publish-BuakG1RK.js} +38 -11
  31. package/dist/{executa-publish-6awuH4Ma.js → executa-publish-CVlMaHIY.js} +3 -3
  32. package/dist/{executa-upload-binaries-FWM2yXfB.js → executa-upload-binaries-BVWs6MFF.js} +2 -2
  33. package/dist/{executa-upload-binaries-DwWQ18Dq.js → executa-upload-binaries-D0JWYOtK.js} +1 -1
  34. package/dist/{listing-meta-DgweMStT.js → listing-meta-rIni8tjd.js} +1 -1
  35. package/dist/{manifest-B_DjigtQ.js → manifest-BCHiC184.js} +49 -3
  36. package/dist/{publish-D5O5JKRb.js → publish-4C5_TgyZ.js} +13 -10
  37. package/dist/{server-Dr_htFv8.js → server-CBx61J7s.js} +91 -1
  38. package/dist/{storage-aii8EyPC.js → storage-CZ4c4ibf.js} +1 -1
  39. package/dist/{working-orchestration-CpBJLs50.js → working-orchestration-BPMFemcH.js} +9 -5
  40. package/package.json +5 -4
  41. package/templates/minimal/manifest.json +0 -1
  42. package/dist/apps-publish-4IIbF2xr.js +0 -17
  43. package/dist/apps-publish-8N9x4VEM.js +0 -272
  44. package/dist/apps-push-CnSeLwdo.js +0 -152
  45. package/dist/bridge-BP28T06H.js +0 -3
  46. package/dist/dev-CnDh2_7r.js +0 -4
  47. package/dist/executa-install-LaAOSkY0.js +0 -7
  48. /package/dist/{confirm-ChZAVrZe.js → confirm-DplLyBSG.js} +0 -0
  49. /package/dist/{dev-account-CfVdGa9j.js → dev-account-IrYL4u4F.js} +0 -0
  50. /package/dist/{dev-app-cache-Dw2JESld.js → dev-app-cache-CScRa7c3.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
@@ -61,8 +61,8 @@ async function runDev(opts) {
61
61
  }
62
62
  process.env.ANNA_APP_RUNTIME_WEB_MODE = "real";
63
63
  }
64
- const { PythonBridge, PINNED_RUNTIME_VERSION } = await import("./bridge-BP28T06H.js");
65
- const { HarnessServer } = await import("./server-Dr_htFv8.js");
64
+ const { PythonBridge, PINNED_RUNTIME_VERSION } = await import("./bridge-nv-le8ff.js");
65
+ const { HarnessServer } = await import("./server-CBx61J7s.js");
66
66
  const bridge = new PythonBridge({
67
67
  mode,
68
68
  matrixNexusRoot: matrixNexusRoot ?? void 0,
@@ -125,8 +125,10 @@ async function runDev(opts) {
125
125
  if (llm === null) return 2;
126
126
  llm.storageMode = storageMode;
127
127
  llm.webMode = webMode;
128
+ llm.appManifest = manifest;
129
+ llm.strictStorageCaps = opts.strictCaps !== false;
128
130
  console.log(` llm bridge ${dim(llm.mode === "off" ? "disabled (--no-llm)" : llm.mode === "mock" ? `mock (${opts.mockLlm})` : `real${opts.llmAccount ? ` [${opts.llmAccount}]` : ""} → app_slug=${llm.appSlug}`)}`);
129
- console.log(` storage backend ${dim(storageMode === "aps" ? "aps (real nexus APS via /api/v1/storage/*)" : "legacy (in-memory runtime_state)")}`);
131
+ console.log(` storage backend ${dim(storageMode === "aps" ? `aps (real nexus APS via /api/v1/storage/*) · caps gate ${opts.strictCaps !== false ? "strict (production parity)" : "warn-only (--no-strict-caps)"}` : "legacy (in-memory runtime_state)")}`);
130
132
  console.log(` web backend ${dim(webMode === "real" ? "real (platform web service via /api/v1/copilot/app/web/* — normal CU billing)" : "local (keyless ddgs + stdlib SSRF fetcher, unbilled)")}`);
131
133
  const server = new HarnessServer({
132
134
  slug,
@@ -175,7 +177,7 @@ async function runDev(opts) {
175
177
  */
176
178
  async function resolveRealLlm(args) {
177
179
  const { getAccount } = await import("./credentials-Chkoidh5.js");
178
- const { ensureDevAppRegistered } = await import("./dev-app-cache-Dw2JESld.js");
180
+ const { ensureDevAppRegistered } = await import("./dev-app-cache-CScRa7c3.js");
179
181
  const acc = getAccount(args.account);
180
182
  if (!acc) {
181
183
  console.error(red("✗ no developer PAT on disk — run `anna-app login --host <nexus-url>` first.\n (or use `--no-llm` / `--mock-llm <fixture>` to develop offline.)"));
@@ -204,7 +206,7 @@ async function resolveRealLlm(args) {
204
206
  account: args.account,
205
207
  appSlug: entry.slug,
206
208
  onAppSlugNotFound: async () => {
207
- const { invalidateDevAppCache } = await import("./dev-app-cache-Dw2JESld.js");
209
+ const { invalidateDevAppCache } = await import("./dev-app-cache-CScRa7c3.js");
208
210
  invalidateDevAppCache(args.cwd);
209
211
  const fresh = getAccount(args.account);
210
212
  if (!fresh) throw new Error("PAT not found while re-registering dev app — run `anna-app login` again");
@@ -1,5 +1,5 @@
1
1
  import { findMatrixNexusRoot, nexusSchemaDir } from "./nexus-root-BlPwOusj.js";
2
- import { PINNED_RUNTIME_VERSION } from "./bridge-sFHqOOat.js";
2
+ import { PINNED_RUNTIME_VERSION } from "./bridge-Bo8eu3-d.js";
3
3
  import { resolve } from "node:path";
4
4
  import { existsSync, statSync } from "node:fs";
5
5
  import { spawnSync } from "node:child_process";
@@ -2,7 +2,7 @@ import "./credentials-BTv2IfUZ.js";
2
2
  import { CliError } from "./client-sMzq2PWG.js";
3
3
  import { resolveClient, withErrorHandling } from "./_lifecycle-shared-_9BzQ9Y2.js";
4
4
  import { deleteMyTool, listMyTools, listToolVersions, unpublishTool, yankToolVersion } from "./executas-CvQY_w2U.js";
5
- import { ensureDestructiveAllowed } from "./confirm-ChZAVrZe.js";
5
+ import { ensureDestructiveAllowed } from "./confirm-DplLyBSG.js";
6
6
  import { dim, green, yellow } from "kleur/colors";
7
7
 
8
8
  //#region src/commands/executa-destructive.ts
@@ -1,5 +1,5 @@
1
1
  import "./nexus-root-BlPwOusj.js";
2
- import { parseExecutaSpec } from "./dev-Bfv3WQC0.js";
2
+ import { parseExecutaSpec } from "./dev-uagVfV9Y.js";
3
3
  import { isAbsolute, resolve } from "node:path";
4
4
  import { existsSync } from "node:fs";
5
5
  import { bold, cyan, dim, green, red, yellow } from "kleur/colors";
@@ -35,7 +35,7 @@ async function runExecutaDev(opts) {
35
35
  const oneShot = !!(opts.describe || opts.health || opts.invoke);
36
36
  const quiet = oneShot && (opts.json ?? false);
37
37
  const { getAccount } = await import("./credentials-Chkoidh5.js");
38
- const { ensureDevExecutaRegistered } = await import("./dev-app-cache-Dw2JESld.js");
38
+ const { ensureDevExecutaRegistered } = await import("./dev-app-cache-CScRa7c3.js");
39
39
  const needsRealMint = !opts.noSampling && !opts.mockSampling || !opts.noAgent && !opts.mockAgent || !opts.noImage && !opts.mockImage || !opts.noUpload && !opts.mockUpload || opts.storage === "real";
40
40
  let effectiveAppSlug = opts.appSlug;
41
41
  let autoRegistered = false;
@@ -57,7 +57,7 @@ async function runExecutaDev(opts) {
57
57
  }
58
58
  }
59
59
  }
60
- const { SamplingBridge } = await import("./sampling-BpJcd6BC.js");
60
+ const { SamplingBridge } = await import("./sampling-BQwF3O-4.js");
61
61
  const simulateUnsupportedResponseFormat = opts.samplingUnsupportedFormat;
62
62
  const sampling = opts.noSampling ? new SamplingBridge({ mode: "off" }) : opts.mockSampling ? new SamplingBridge({
63
63
  mode: "mock",
@@ -69,7 +69,7 @@ async function runExecutaDev(opts) {
69
69
  appSlug: effectiveAppSlug,
70
70
  simulateUnsupportedResponseFormat
71
71
  }) : new SamplingBridge({ mode: "off" });
72
- const { AgentBridge } = await import("./agent-DAOr_aiE.js");
72
+ const { AgentBridge } = await import("./agent-CX2VzG7e.js");
73
73
  const agent = opts.noAgent ? new AgentBridge({ mode: "off" }) : opts.mockAgent ? new AgentBridge({
74
74
  mode: "mock",
75
75
  mockFile: opts.mockAgent
@@ -78,7 +78,7 @@ async function runExecutaDev(opts) {
78
78
  account: opts.agentAccount ?? opts.samplingAccount,
79
79
  appSlug: effectiveAppSlug
80
80
  }) : new AgentBridge({ mode: "off" });
81
- const { StorageBridge } = await import("./storage-aii8EyPC.js");
81
+ const { StorageBridge } = await import("./storage-CZ4c4ibf.js");
82
82
  const storageMode = opts.storage ?? (opts.mockStorage ? "mock" : "memory");
83
83
  const storage = new StorageBridge({
84
84
  mode: storageMode,
@@ -88,8 +88,8 @@ async function runExecutaDev(opts) {
88
88
  scopes: opts.storageScopes ? opts.storageScopes.split(",").map((s) => s.trim()).filter(Boolean) : void 0,
89
89
  pluginName: parsed.tool_id
90
90
  });
91
- const { ExecutaRunner } = await import("./runner-Dq3cluPM.js");
92
- const { ImageBridge } = await import("./image-B4UrufYH.js");
91
+ const { ExecutaRunner } = await import("./runner-aq0n-pdr.js");
92
+ const { ImageBridge } = await import("./image-C61zRJC8.js");
93
93
  const image = opts.noImage ? new ImageBridge({ mode: "off" }) : opts.mockImage ? new ImageBridge({
94
94
  mode: "mock",
95
95
  mockFile: opts.mockImage
@@ -98,7 +98,7 @@ async function runExecutaDev(opts) {
98
98
  account: opts.imageAccount ?? opts.samplingAccount,
99
99
  appSlug: effectiveAppSlug
100
100
  }) : new ImageBridge({ mode: "off" });
101
- const { HostUploadBridge } = await import("./host_upload-CW_2Fxg6.js");
101
+ const { HostUploadBridge } = await import("./host_upload-BvzJZKAO.js");
102
102
  const hostUpload = opts.noUpload ? new HostUploadBridge({ mode: "off" }) : opts.mockUpload ? new HostUploadBridge({
103
103
  mode: "mock",
104
104
  mockFile: opts.mockUpload
@@ -0,0 +1,7 @@
1
+ import "./credentials-BTv2IfUZ.js";
2
+ import "./nexus-root-BlPwOusj.js";
3
+ import "./executa-cache-BFoUtb4J.js";
4
+ import "./dev-uagVfV9Y.js";
5
+ import { runExecutaInstall } from "./executa-install-u0nXcyy7.js";
6
+
7
+ export { runExecutaInstall };
@@ -1,5 +1,5 @@
1
1
  import { readExecutaIdentity } from "./executa-cache-BFoUtb4J.js";
2
- import { parseExecutaSpec } from "./dev-Bfv3WQC0.js";
2
+ import { parseExecutaSpec } from "./dev-uagVfV9Y.js";
3
3
  import { isAbsolute, join, resolve } from "node:path";
4
4
  import { chmodSync, existsSync, mkdirSync, writeFileSync } from "node:fs";
5
5
  import { bold, cyan, dim, green, red, yellow } from "kleur/colors";
@@ -2,9 +2,9 @@ import { canonicalHost } from "./credentials-BTv2IfUZ.js";
2
2
  import { CliError } from "./client-sMzq2PWG.js";
3
3
  import { resolveClient, withErrorHandling } from "./_lifecycle-shared-_9BzQ9Y2.js";
4
4
  import { executaCacheMatches, invalidateExecutaCache, mintIdempotencyKey, readExecutaIdentity, writeExecutaIdentity } from "./executa-cache-BFoUtb4J.js";
5
- import { loadExecutaManifest } from "./manifest-B_DjigtQ.js";
5
+ import { loadExecutaManifest, protocolHostCapabilities } from "./manifest-BCHiC184.js";
6
6
  import { commitDraft, createDraft, getMySkill, getMyTool, listToolVersions, publishToolVersion, setSkillVisibility, setToolVisibility, updateMySkill, updateMyTool } from "./executas-CvQY_w2U.js";
7
- import { uploadExecutaBinaries } from "./executa-upload-binaries-DwWQ18Dq.js";
7
+ import { uploadExecutaBinaries } from "./executa-upload-binaries-D0JWYOtK.js";
8
8
  import { join, relative, resolve, sep } from "node:path";
9
9
  import { readFileSync, readdirSync, statSync, writeFileSync } from "node:fs";
10
10
  import { bold, cyan, dim, green, yellow } from "kleur/colors";
@@ -169,7 +169,8 @@ async function runExecutaPublish(opts) {
169
169
  executa_type: manifest.executa_type,
170
170
  slug: manifest.slug,
171
171
  version: manifest.version,
172
- ...distributionPayload(manifest.distribution)
172
+ ...distributionPayload(manifest.distribution),
173
+ ...manifest.protocolManifest ? { manifest_cache: manifest.protocolManifest } : {}
173
174
  };
174
175
  if (manifest.executa_type === "skill") {
175
176
  finalPayload.skill_content = manifest.skillContent;
@@ -202,12 +203,22 @@ async function runExecutaPublish(opts) {
202
203
  version: manifest.version,
203
204
  ...manifest.executionMode ? { skill_execution_mode: manifest.executionMode } : {}
204
205
  });
205
- else await updateMyTool(client, executaId, {
206
- name: manifest.name,
207
- description: manifest.description,
208
- version: manifest.version,
209
- ...distributionPayload(manifest.distribution)
210
- });
206
+ else {
207
+ await updateMyTool(client, executaId, {
208
+ name: manifest.name,
209
+ description: manifest.description,
210
+ version: manifest.version,
211
+ ...distributionPayload(manifest.distribution),
212
+ ...manifest.protocolManifest ? { manifest_cache: manifest.protocolManifest } : {}
213
+ });
214
+ if (!opts.json && !opts.quiet) {
215
+ if (manifest.protocolManifest && manifest.protocolManifestPath) {
216
+ const caps = protocolHostCapabilities(manifest.protocolManifest);
217
+ const capsNote = caps.length > 0 ? `${caps.length} host capabilit${caps.length === 1 ? "y" : "ies"}: ${caps.join(", ")}` : "no host_capabilities declared";
218
+ console.log(dim(` synced protocol manifest (${capsNote}) from ${manifest.protocolManifestPath.replace(cwd + "/", "")}`));
219
+ } else if (manifest.distribution) console.log(yellow("! no protocol manifest found (no `manifest.json` next to executa.json, no `manifest_file` field) — host-capability permissions (host.upload / aps.* / llm.* / web.*) declared by the plugin will NOT be grantable in the Executa permissions UI until an agent-side describe backfills them. Export the plugin's describe manifest to manifest.json and re-publish."));
220
+ }
221
+ }
211
222
  if (!isSkill && manifest.distribution?.binaryArtifacts && opts.freeze !== false) {
212
223
  const upLog = (msg) => {
213
224
  if (!opts.json && !opts.quiet) console.log(msg);
@@ -254,7 +265,10 @@ async function runExecutaPublish(opts) {
254
265
  first_publish: firstPublish,
255
266
  published_public: publishedToPublic,
256
267
  visibility: finalExecuta.visibility ?? null,
257
- latest_version_id: latest?.id ?? null
268
+ latest_version_id: latest?.id ?? null,
269
+ executa_type: manifest.executa_type,
270
+ manifest_synced: Boolean(manifest.protocolManifest),
271
+ host_capabilities: protocolHostCapabilities(manifest.protocolManifest)
258
272
  };
259
273
  opts.capture?.(result);
260
274
  if (opts.quiet) return 0;
@@ -270,6 +284,19 @@ async function runExecutaPublish(opts) {
270
284
  return 0;
271
285
  });
272
286
  }
287
+ /**
288
+ * One-line protocol-manifest sync note for a bundled `executa publish`
289
+ * result, printed by the `apps publish` / `apps push` orchestration
290
+ * (the nested publish itself runs `quiet`). `null` → nothing to print.
291
+ */
292
+ function manifestSyncNote(r) {
293
+ if (r.executa_type !== "tool") return null;
294
+ if (r.manifest_synced) {
295
+ const caps = r.host_capabilities;
296
+ return dim(" protocol manifest synced (" + (caps.length > 0 ? `host capabilities: ${caps.join(", ")}` : "no host_capabilities declared") + ")");
297
+ }
298
+ return yellow(" ! no protocol manifest for this bundled executa — add manifest.json (the plugin's describe response) next to its executa.json so declared host capabilities (host.upload / aps.* / llm.* / web.*) become grantable in the Executa permissions UI");
299
+ }
273
300
 
274
301
  //#endregion
275
- export { bumpVersion, bundleHash, canonicalize, manifestHash, rewriteVersion, runExecutaPublish };
302
+ export { bumpVersion, bundleHash, canonicalize, manifestHash, manifestSyncNote, rewriteVersion, runExecutaPublish };
@@ -2,10 +2,10 @@ import "./credentials-BTv2IfUZ.js";
2
2
  import "./client-sMzq2PWG.js";
3
3
  import "./_lifecycle-shared-_9BzQ9Y2.js";
4
4
  import "./executa-cache-BFoUtb4J.js";
5
- import "./manifest-B_DjigtQ.js";
5
+ import "./manifest-BCHiC184.js";
6
6
  import "./executas-CvQY_w2U.js";
7
- import { runExecutaPublish } from "./executa-publish-BKnsUoZq.js";
7
+ import { manifestSyncNote, runExecutaPublish } from "./executa-publish-BuakG1RK.js";
8
8
  import "./binary-upload-DVhQ0uY0.js";
9
- import "./executa-upload-binaries-DwWQ18Dq.js";
9
+ import "./executa-upload-binaries-D0JWYOtK.js";
10
10
 
11
11
  export { runExecutaPublish };
@@ -2,8 +2,8 @@ import "./credentials-BTv2IfUZ.js";
2
2
  import "./client-sMzq2PWG.js";
3
3
  import "./_lifecycle-shared-_9BzQ9Y2.js";
4
4
  import "./executa-cache-BFoUtb4J.js";
5
- import "./manifest-B_DjigtQ.js";
5
+ import "./manifest-BCHiC184.js";
6
6
  import "./binary-upload-DVhQ0uY0.js";
7
- import { expandArtifactPath, resolveArtifactPlan, runExecutaUploadBinaries, uploadExecutaBinaries, uploadPlannedParts } from "./executa-upload-binaries-DwWQ18Dq.js";
7
+ import { expandArtifactPath, resolveArtifactPlan, runExecutaUploadBinaries, uploadExecutaBinaries, uploadPlannedParts } from "./executa-upload-binaries-D0JWYOtK.js";
8
8
 
9
9
  export { runExecutaUploadBinaries };
@@ -2,7 +2,7 @@ import { canonicalHost } from "./credentials-BTv2IfUZ.js";
2
2
  import { CliError } from "./client-sMzq2PWG.js";
3
3
  import { resolveClient, withErrorHandling } from "./_lifecycle-shared-_9BzQ9Y2.js";
4
4
  import { readExecutaIdentity } from "./executa-cache-BFoUtb4J.js";
5
- import { loadExecutaManifest } from "./manifest-B_DjigtQ.js";
5
+ import { loadExecutaManifest } from "./manifest-BCHiC184.js";
6
6
  import { fetchGitHubIdToken, finalizeBinaryUpload, initBinaryUpload, mintUploadSession, mintUploadSessionViaOidc, uploadBinaryPart } from "./binary-upload-DVhQ0uY0.js";
7
7
  import { isAbsolute, resolve } from "node:path";
8
8
  import { closeSync, createReadStream, existsSync, openSync, readSync, statSync } from "node:fs";
@@ -1,4 +1,4 @@
1
- import { patchApp, uploadAppLogo, uploadAppScreenshot } from "./apps-HbfURK6y.js";
1
+ import { patchApp, uploadAppLogo, uploadAppScreenshot } from "./apps-BRBufSyX.js";
2
2
  import { CliError } from "./client-sMzq2PWG.js";
3
3
  import { extname, resolve } from "node:path";
4
4
  import { existsSync, readFileSync } from "node:fs";
@@ -1,5 +1,5 @@
1
1
  import { CliError } from "./client-sMzq2PWG.js";
2
- import { resolve } from "node:path";
2
+ import { dirname, resolve } from "node:path";
3
3
  import { existsSync, readFileSync } from "node:fs";
4
4
 
5
5
  //#region src/publish/manifest.ts
@@ -118,6 +118,7 @@ function loadExecutaManifest(cwd, manifestPath, profileOverride) {
118
118
  skillContent = readFileSync(contentPath, "utf-8");
119
119
  if (!skillContent.trim()) throw new CliError(`skill content file "${contentFile}" is empty`, 4);
120
120
  }
121
+ const protocol = loadProtocolManifest(path, raw, t);
121
122
  return {
122
123
  kind: "executa",
123
124
  path,
@@ -130,10 +131,55 @@ function loadExecutaManifest(cwd, manifestPath, profileOverride) {
130
131
  changelog: pickString(raw, "changelog") ?? void 0,
131
132
  skillContent,
132
133
  executionMode: pickString(raw, "execution_mode") ?? void 0,
133
- distribution: parseExecutaDistribution(raw["distribution"], t, profileOverride)
134
+ distribution: parseExecutaDistribution(raw["distribution"], t, profileOverride),
135
+ protocolManifest: protocol?.manifest,
136
+ protocolManifestPath: protocol?.path
134
137
  };
135
138
  }
136
139
  /**
140
+ * Load the Executa JSON-RPC protocol manifest for a `tool` Executa.
141
+ *
142
+ * Resolution (relative to the directory holding `executa.json`):
143
+ * 1. explicit `executa.json` `manifest_file` path — must exist;
144
+ * 2. sibling `manifest.json` convention — optional.
145
+ *
146
+ * Returns `undefined` when no protocol manifest is available (the server
147
+ * `manifest_cache` field is then simply not synced — backwards compatible).
148
+ */
149
+ function loadProtocolManifest(executaJsonPath, raw, executaType) {
150
+ const declared = raw["manifest_file"];
151
+ if (declared !== void 0 && typeof declared !== "string") throw new CliError("executa.json `manifest_file` must be a string path", 4);
152
+ if (executaType === "skill") {
153
+ if (declared) throw new CliError("executa.json `manifest_file` is only valid for `executa_type: \"tool\"` — skills have no JSON-RPC protocol manifest", 4);
154
+ return void 0;
155
+ }
156
+ const dir = dirname(executaJsonPath);
157
+ const path = resolve(dir, declared ?? "manifest.json");
158
+ if (!existsSync(path)) {
159
+ if (declared) throw new CliError(`executa.json \`manifest_file\` points at "${declared}" but ${path} does not exist`, 4);
160
+ return void 0;
161
+ }
162
+ const manifest = readJson(path);
163
+ const caps = manifest["host_capabilities"] ?? manifest["hostCapabilities"];
164
+ if (caps !== void 0 && caps !== null) {
165
+ const isStrArray = Array.isArray(caps) && caps.every((c) => typeof c === "string");
166
+ const isBoolMap = !Array.isArray(caps) && typeof caps === "object" && Object.values(caps).every((v) => typeof v === "boolean");
167
+ if (!isStrArray && !isBoolMap) throw new CliError(`protocol manifest ${path} \`host_capabilities\` must be an array of strings (or a {capability: bool} map)`, 4);
168
+ }
169
+ return {
170
+ manifest,
171
+ path
172
+ };
173
+ }
174
+ /** Declared host capability strings of a protocol manifest (normalised). */
175
+ function protocolHostCapabilities(manifest) {
176
+ if (!manifest) return [];
177
+ const caps = manifest["host_capabilities"] ?? manifest["hostCapabilities"];
178
+ if (Array.isArray(caps)) return caps.filter((c) => typeof c === "string");
179
+ if (caps && typeof caps === "object") return Object.entries(caps).filter(([, v]) => v === true).map(([k]) => k);
180
+ return [];
181
+ }
182
+ /**
137
183
  * Parse + validate the optional `executa.json` `distribution` object.
138
184
  *
139
185
  * Returns `undefined` when absent (a dev-only Executa). Skills never carry
@@ -335,4 +381,4 @@ function pickStringArray(o, k) {
335
381
  }
336
382
 
337
383
  //#endregion
338
- export { loadAppManifest, loadExecutaManifest };
384
+ export { loadAppManifest, loadExecutaManifest, protocolHostCapabilities };
@@ -1,18 +1,23 @@
1
1
  import "./credentials-BTv2IfUZ.js";
2
- import "./apps-HbfURK6y.js";
2
+ import "./nexus-root-BlPwOusj.js";
3
+ import "./apps-BRBufSyX.js";
3
4
  import { CliError } from "./client-sMzq2PWG.js";
4
5
  import { withErrorHandling } from "./_lifecycle-shared-_9BzQ9Y2.js";
5
6
  import "./executa-cache-BFoUtb4J.js";
6
7
  import "./bundled-executas-BRyQkI9u.js";
7
- import "./manifest-B_DjigtQ.js";
8
+ import "./manifest-BCHiC184.js";
8
9
  import "./executas-CvQY_w2U.js";
9
- import { runExecutaPublish } from "./executa-publish-BKnsUoZq.js";
10
+ import { runExecutaPublish } from "./executa-publish-BuakG1RK.js";
10
11
  import "./binary-upload-DVhQ0uY0.js";
11
- import "./executa-upload-binaries-DwWQ18Dq.js";
12
+ import "./executa-upload-binaries-D0JWYOtK.js";
13
+ import "./dev-uagVfV9Y.js";
14
+ import "./executa-install-u0nXcyy7.js";
12
15
  import "./app-cache-Cr3tKbux.js";
13
- import "./listing-meta-DgweMStT.js";
14
- import "./app-bundle-upload-Ca0r-kPy.js";
15
- import { runAppsPublish } from "./apps-publish-8N9x4VEM.js";
16
+ import "./working-orchestration-BPMFemcH.js";
17
+ import "./apps-cut-BLtUBokD.js";
18
+ import "./listing-meta-rIni8tjd.js";
19
+ import "./apps-push-DZ1LHDJW.js";
20
+ import { runAppsPublish } from "./apps-publish-BzaoSyFn.js";
16
21
  import { resolve } from "node:path";
17
22
  import { existsSync } from "node:fs";
18
23
  import { red, yellow } from "kleur/colors";
@@ -21,9 +26,8 @@ import { red, yellow } from "kleur/colors";
21
26
  function detectProjectKind(cwd) {
22
27
  const hasManifest = existsSync(resolve(cwd, "manifest.json"));
23
28
  const hasExecuta = existsSync(resolve(cwd, "executa.json"));
24
- if (hasManifest && hasExecuta) return "ambiguous";
25
- if (hasManifest) return "app";
26
29
  if (hasExecuta) return "executa";
30
+ if (hasManifest) return "app";
27
31
  return "unknown";
28
32
  }
29
33
 
@@ -33,7 +37,6 @@ async function runTopLevelPublish(opts) {
33
37
  return withErrorHandling(async () => {
34
38
  const cwd = resolve(opts.cwd ?? process.cwd());
35
39
  const kind = detectProjectKind(cwd);
36
- if (kind === "ambiguous") throw new CliError(`cannot auto-detect: ${cwd} has BOTH manifest.json and executa.json. Run \`anna-app apps publish\` or \`anna-app executa publish\` explicitly.`, 4);
37
40
  if (kind === "unknown") throw new CliError(`no manifest.json or executa.json found in ${cwd}`, 4);
38
41
  if (kind === "app") return runAppsPublish({
39
42
  cwd,
@@ -1,5 +1,5 @@
1
1
  import { canonicalHost, getAccount } from "./credentials-BTv2IfUZ.js";
2
- import { BridgeRequestError } from "./bridge-sFHqOOat.js";
2
+ import { BridgeRequestError } from "./bridge-Bo8eu3-d.js";
3
3
  import { dirname, join, normalize, resolve } from "node:path";
4
4
  import { createRequire } from "node:module";
5
5
  import { createReadStream, existsSync, readFileSync, statSync, watch } from "node:fs";
@@ -9,6 +9,71 @@ import { createServer } from "node:http";
9
9
  import { WebSocketServer } from "ws";
10
10
  import { setTimeout as setTimeout$1 } from "node:timers/promises";
11
11
 
12
+ //#region src/executa/storage-caps.ts
13
+ /**
14
+ * APS storage declaration predicates — TS mirror of the canonical Python
15
+ * module `matrix-nexus/packages/anna-app-core/src/anna_app_core/storage_decl.py`
16
+ * (design aps-authorization-simplification.md §4.3).
17
+ *
18
+ * ⚠️ The constant tables below are diffed against the Python source by
19
+ * `scripts/check-storage-caps-sync.mjs` in CI — change BOTH sides together.
20
+ */
21
+ /** Plugin-side storage_token mint trigger set (bare "aps" = historic umbrella). */
22
+ const PLUGIN_STORAGE_CAPS = [
23
+ "aps.kv",
24
+ "aps.files",
25
+ "aps"
26
+ ];
27
+ const APS_SCOPE_PREFIX = "aps.scope.";
28
+ const STORAGE_SCOPES = new Set([
29
+ "user",
30
+ "app",
31
+ "tool"
32
+ ]);
33
+ const STORAGE_MODES = new Set([
34
+ "r",
35
+ "w",
36
+ "rw"
37
+ ]);
38
+ /** Whether a `host_capabilities` set triggers plugin-side storage_token
39
+ * minting. Wide convergence: `aps.scope.*` counts the same as
40
+ * `aps.kv`/`aps.files` (forum #284). */
41
+ function declaresPluginStorage(caps) {
42
+ for (const c of caps) {
43
+ if (PLUGIN_STORAGE_CAPS.includes(c)) return true;
44
+ if (c.startsWith(APS_SCOPE_PREFIX)) return true;
45
+ }
46
+ return false;
47
+ }
48
+ /** Extract `host_capabilities` from a manifest-like object (list or
49
+ * `{cap: bool}` dict form). */
50
+ function extractHostCapabilities(manifest) {
51
+ const raw = manifest?.host_capabilities ?? manifest?.hostCapabilities;
52
+ if (Array.isArray(raw)) return raw.map(String);
53
+ if (raw && typeof raw === "object") return Object.entries(raw).filter(([, v]) => !!v).map(([k]) => k);
54
+ return [];
55
+ }
56
+ /** Whether a full manifest declares plugin storage via EITHER form: legacy
57
+ * aps.* capability strings or the structured schema-3 `storage` entry. */
58
+ function manifestDeclaresPluginStorage(manifest) {
59
+ if (!manifest) return false;
60
+ if (declaresPluginStorage(extractHostCapabilities(manifest))) return true;
61
+ const storage = manifest.storage;
62
+ if (storage && typeof storage === "object" && !Array.isArray(storage)) {
63
+ const s = storage;
64
+ if (s.kv || s.files) return true;
65
+ if (s.scopes && typeof s.scopes === "object") {
66
+ for (const [scope, mode] of Object.entries(s.scopes)) if (STORAGE_SCOPES.has(scope) && STORAGE_MODES.has(String(mode))) return true;
67
+ }
68
+ }
69
+ return false;
70
+ }
71
+ /** Production-parity error body for an unminted storage_token (matrix host
72
+ * `src/executa/storage.py` wording, verbatim) + a local-only fix hint. */
73
+ const STORAGE_TOKEN_MISSING_ERROR = "-32021: storage_token missing — host did not authorize storage for this invoke";
74
+ const STORAGE_CAPS_HINT = "hint: declare \"aps.kv\" (KV) / \"aps.files\" (Files) in host_capabilities; the platform will not mint a plugin storage_token without them (docs: executa-storage)";
75
+
76
+ //#endregion
12
77
  //#region src/harness/llm-bridge.ts
13
78
  /** APS-mode ``storage`` methods the bridge forwards to ``/api/v1/storage/*``.
14
79
  * ``get/set/delete/list`` are the KV family; ``files_*`` are the object/blob
@@ -117,6 +182,30 @@ var LlmBridge = class {
117
182
  mintedStorage = null;
118
183
  mocks = [];
119
184
  streamCounter = 0;
185
+ warnedStorageCaps = false;
186
+ /** Production-parity storage caps gate (aps-authorization-simplification
187
+ * §4.3): in prod, no `storage_token` is minted unless the manifest
188
+ * declares storage — the invoke fails with `-32021` BEFORE scope
189
+ * evaluation. Enforced for non-self scopes (`user`/`tool`) and the
190
+ * executa reverse-RPC `files_*` family; iframe self app-scope needs no
191
+ * capability declaration in prod either. */
192
+ assertStorageCaps(method, a) {
193
+ const manifest = this.opts.appManifest;
194
+ if (!manifest) return;
195
+ const scope = String(a?.scope ?? "app");
196
+ const reverseRpcFiles = method.startsWith("files_");
197
+ if (scope === "app" && !reverseRpcFiles) return;
198
+ if (manifestDeclaresPluginStorage(manifest)) return;
199
+ if (this.opts.strictStorageCaps === false) {
200
+ if (!this.warnedStorageCaps) {
201
+ this.warnedStorageCaps = true;
202
+ console.warn(`\n⚠ [storage-caps] ${STORAGE_TOKEN_MISSING_ERROR}\n⚠ [storage-caps] ${STORAGE_CAPS_HINT}\n⚠ [storage-caps] proceeding anyway (--no-strict-caps) — this WILL fail in production
203
+ `);
204
+ }
205
+ return;
206
+ }
207
+ throw new Error(`${STORAGE_TOKEN_MISSING_ERROR}\n${STORAGE_CAPS_HINT}`);
208
+ }
120
209
  constructor(opts) {
121
210
  this.opts = opts;
122
211
  if (opts.mode === "mock" && opts.mockFile) {
@@ -740,6 +829,7 @@ var LlmBridge = class {
740
829
  };
741
830
  }
742
831
  if (args.ns === "storage") {
832
+ this.assertStorageCaps(args.method, args.args);
743
833
  const sm = await this.mintStorage();
744
834
  const a = args.args;
745
835
  const base = `${canonicalHost(acc.host)}/api/v1/storage`;
@@ -1,5 +1,5 @@
1
1
  import { canonicalHost } from "./credentials-BTv2IfUZ.js";
2
- import { hostOf, requireAccount, withCode } from "./dev-account-CfVdGa9j.js";
2
+ import { hostOf, requireAccount, withCode } from "./dev-account-IrYL4u4F.js";
3
3
  import { resolve } from "node:path";
4
4
  import { existsSync, readFileSync } from "node:fs";
5
5
 
@@ -1,10 +1,10 @@
1
1
  import { canonicalHost } from "./credentials-BTv2IfUZ.js";
2
- import { createApp, findAppBySlug, getApp } from "./apps-HbfURK6y.js";
2
+ import { createApp, findAppBySlug, getApp } from "./apps-BRBufSyX.js";
3
3
  import { CliError } from "./client-sMzq2PWG.js";
4
4
  import { parseExecutaIdOverrides, readExecutasLock, substituteBundledRefs, validateBundledHandles, writeBundleToolIdSidecar, writeExecutasLock } from "./bundled-executas-BRyQkI9u.js";
5
- import { loadExecutaManifest } from "./manifest-B_DjigtQ.js";
6
- import { runExecutaPublish } from "./executa-publish-BKnsUoZq.js";
7
- import { runExecutaInstall } from "./executa-install-DAposiBw.js";
5
+ import { loadExecutaManifest } from "./manifest-BCHiC184.js";
6
+ import { manifestSyncNote, runExecutaPublish } from "./executa-publish-BuakG1RK.js";
7
+ import { runExecutaInstall } from "./executa-install-u0nXcyy7.js";
8
8
  import { appCacheMatches, readAppIdentity, writeAppIdentity } from "./app-cache-Cr3tKbux.js";
9
9
  import { join, resolve } from "node:path";
10
10
  import { dim, green, yellow } from "kleur/colors";
@@ -72,7 +72,11 @@ async function resolveBundledExecutas(params) {
72
72
  path: decl.path,
73
73
  source: params.lockSource ?? (freeze ? "published" : "working")
74
74
  };
75
- if (!json) console.log(green(` ✓ bundled:${decl.handle} → ${captured.tool_id}`) + dim(` (v${captured.version}${captured.idempotent_hit ? ", unchanged" : ""})`));
75
+ if (!json) {
76
+ console.log(green(` ✓ bundled:${decl.handle} → ${captured.tool_id}`) + dim(` (v${captured.version}${captured.idempotent_hit ? ", unchanged" : ""})`));
77
+ const note = manifestSyncNote(captured);
78
+ if (note) console.log(note);
79
+ }
76
80
  }
77
81
  for (const o of overrides) if (!(o.handle in resolved)) {
78
82
  resolved[o.handle] = o.toolId;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@anna-ai/cli",
3
- "version": "0.1.49",
3
+ "version": "0.1.52",
4
4
  "description": "Anna App developer CLI: scaffold, validate, harness (Phase 2 MVP: init + validate).",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -30,11 +30,12 @@
30
30
  "lint": "tsc --noEmit",
31
31
  "check:runtime-pin": "node scripts/check-runtime-pin.mjs",
32
32
  "check:sdk-pin": "node scripts/check-sdk-pin.mjs",
33
- "prepublishOnly": "pnpm lint && pnpm test && pnpm build && node scripts/check-runtime-pin.mjs && node scripts/check-sdk-pin.mjs"
33
+ "check:storage-caps": "node scripts/check-storage-caps-sync.mjs",
34
+ "prepublishOnly": "pnpm lint && pnpm test && pnpm build && node scripts/check-runtime-pin.mjs && node scripts/check-sdk-pin.mjs && node scripts/check-storage-caps-sync.mjs"
34
35
  },
35
36
  "dependencies": {
36
- "@anna-ai/app-runtime": "^0.15.0",
37
- "@anna-ai/app-schema": "^0.19.0",
37
+ "@anna-ai/app-runtime": "^0.16.0",
38
+ "@anna-ai/app-schema": "^0.22.0",
38
39
  "ajv": "^8.17.1",
39
40
  "ajv-formats": "^3.0.1",
40
41
  "commander": "^12.1.0",
@@ -1,6 +1,5 @@
1
1
  {
2
2
  "schema": 2,
3
- "permissions": ["tools.invoke", "storage.read", "storage.write"],
4
3
  "required_executas": [
5
4
  {
6
5
  "tool_id": "__TOOL_ID__"
@@ -1,17 +0,0 @@
1
- import "./credentials-BTv2IfUZ.js";
2
- import "./apps-HbfURK6y.js";
3
- import "./client-sMzq2PWG.js";
4
- import "./_lifecycle-shared-_9BzQ9Y2.js";
5
- import "./executa-cache-BFoUtb4J.js";
6
- import "./bundled-executas-BRyQkI9u.js";
7
- import "./manifest-B_DjigtQ.js";
8
- import "./executas-CvQY_w2U.js";
9
- import "./executa-publish-BKnsUoZq.js";
10
- import "./binary-upload-DVhQ0uY0.js";
11
- import "./executa-upload-binaries-DwWQ18Dq.js";
12
- import "./app-cache-Cr3tKbux.js";
13
- import "./listing-meta-DgweMStT.js";
14
- import "./app-bundle-upload-Ca0r-kPy.js";
15
- import { runAppsPublish } from "./apps-publish-8N9x4VEM.js";
16
-
17
- export { runAppsPublish };