@anna-ai/cli 0.1.51 → 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.
- package/dist/{apps-cut-L7T8b5RS.js → apps-cut-BLtUBokD.js} +1 -1
- package/dist/{apps-cut-35wivw1Z.js → apps-cut-eOVb1-0y.js} +4 -4
- package/dist/{apps-discard-CKA_m7Yw.js → apps-discard-7ERq2pmS.js} +3 -3
- package/dist/{apps-grants-B5MpWhSO.js → apps-grants-DVoSb6-r.js} +6 -1
- package/dist/{apps-publish-CUJILNOt.js → apps-publish-AdXryRYo.js} +6 -6
- package/dist/{apps-publish-CGfzN7tI.js → apps-publish-BzaoSyFn.js} +2 -2
- package/dist/{apps-push-d1C0eePp.js → apps-push-DZ1LHDJW.js} +1 -1
- package/dist/{apps-push-BcYNGSYx.js → apps-push-WBfD0JyE.js} +4 -4
- package/dist/{apps-release-DxRHjEYJ.js → apps-release-DAV-DB_Q.js} +1 -1
- package/dist/cli.js +145 -20
- package/dist/dev-CQIZHt7u.js +4 -0
- package/dist/{dev-BB1oS-1o.js → dev-uagVfV9Y.js} +4 -2
- package/dist/{executa-dev-ONm9di1H.js → executa-dev-BeYhrj-n.js} +1 -1
- package/dist/executa-install-Dnerah9u.js +7 -0
- package/dist/{executa-install-n1oRAoYJ.js → executa-install-u0nXcyy7.js} +1 -1
- package/dist/{publish-CIaosgo4.js → publish-4C5_TgyZ.js} +6 -6
- package/dist/{server-poDjwty-.js → server-CBx61J7s.js} +90 -0
- package/dist/{working-orchestration-BRU7FV-b.js → working-orchestration-BPMFemcH.js} +1 -1
- package/package.json +3 -2
- package/templates/minimal/manifest.json +0 -1
- package/dist/dev-DAkNdyJ-.js +0 -4
- package/dist/executa-install-DKMwLq-V.js +0 -7
|
@@ -6,7 +6,7 @@ import { readExecutaIdentity } from "./executa-cache-BFoUtb4J.js";
|
|
|
6
6
|
import { readExecutasLock, writeExecutasLock } from "./bundled-executas-BRyQkI9u.js";
|
|
7
7
|
import { loadAppManifest, loadExecutaManifest } from "./manifest-BCHiC184.js";
|
|
8
8
|
import { uploadExecutaBinaries } from "./executa-upload-binaries-D0JWYOtK.js";
|
|
9
|
-
import { resolveAppBySlugOrCache } from "./working-orchestration-
|
|
9
|
+
import { resolveAppBySlugOrCache } from "./working-orchestration-BPMFemcH.js";
|
|
10
10
|
import { resolve } from "node:path";
|
|
11
11
|
import { existsSync } from "node:fs";
|
|
12
12
|
import { bold, cyan, dim, green, yellow } from "kleur/colors";
|
|
@@ -10,10 +10,10 @@ import "./executas-CvQY_w2U.js";
|
|
|
10
10
|
import "./executa-publish-BuakG1RK.js";
|
|
11
11
|
import "./binary-upload-DVhQ0uY0.js";
|
|
12
12
|
import "./executa-upload-binaries-D0JWYOtK.js";
|
|
13
|
-
import "./dev-
|
|
14
|
-
import "./executa-install-
|
|
13
|
+
import "./dev-uagVfV9Y.js";
|
|
14
|
+
import "./executa-install-u0nXcyy7.js";
|
|
15
15
|
import "./app-cache-Cr3tKbux.js";
|
|
16
|
-
import "./working-orchestration-
|
|
17
|
-
import { runAppsCut } from "./apps-cut-
|
|
16
|
+
import "./working-orchestration-BPMFemcH.js";
|
|
17
|
+
import { runAppsCut } from "./apps-cut-BLtUBokD.js";
|
|
18
18
|
|
|
19
19
|
export { runAppsCut };
|
|
@@ -10,10 +10,10 @@ import "./executas-CvQY_w2U.js";
|
|
|
10
10
|
import "./executa-publish-BuakG1RK.js";
|
|
11
11
|
import "./binary-upload-DVhQ0uY0.js";
|
|
12
12
|
import "./executa-upload-binaries-D0JWYOtK.js";
|
|
13
|
-
import "./dev-
|
|
14
|
-
import "./executa-install-
|
|
13
|
+
import "./dev-uagVfV9Y.js";
|
|
14
|
+
import "./executa-install-u0nXcyy7.js";
|
|
15
15
|
import "./app-cache-Cr3tKbux.js";
|
|
16
|
-
import { resolveAppBySlugOrCache } from "./working-orchestration-
|
|
16
|
+
import { resolveAppBySlugOrCache } from "./working-orchestration-BPMFemcH.js";
|
|
17
17
|
import { dim, green, yellow } from "kleur/colors";
|
|
18
18
|
|
|
19
19
|
//#region src/commands/apps-discard.ts
|
|
@@ -49,12 +49,17 @@ async function runAppsGrants(opts) {
|
|
|
49
49
|
const executas = perms.executas ?? [];
|
|
50
50
|
if (executas.length > 0) {
|
|
51
51
|
console.log(bold(cyan("bundled executa grants")));
|
|
52
|
+
let sawStorageGrant = false;
|
|
52
53
|
for (const ex of executas) {
|
|
53
54
|
console.log(` ${String(ex.name ?? ex.executa_id)}:`);
|
|
54
55
|
const sections = executaGrantSections(ex);
|
|
55
56
|
if (Object.keys(sections).length === 0) console.log(dim(" (no grants configured)"));
|
|
56
|
-
else for (const [k, v] of Object.entries(sections))
|
|
57
|
+
else for (const [k, v] of Object.entries(sections)) {
|
|
58
|
+
if (k === "storage_grant") sawStorageGrant = true;
|
|
59
|
+
console.log(` ${k}: ${JSON.stringify(v)}`);
|
|
60
|
+
}
|
|
57
61
|
}
|
|
62
|
+
if (sawStorageGrant) console.log(dim(" storage scopes: user, tool (platform-fixed; scope=app is Host-API only)"));
|
|
58
63
|
}
|
|
59
64
|
const missing = perms.missing ?? [];
|
|
60
65
|
if (missing.length > 0) {
|
|
@@ -10,13 +10,13 @@ import "./executas-CvQY_w2U.js";
|
|
|
10
10
|
import "./executa-publish-BuakG1RK.js";
|
|
11
11
|
import "./binary-upload-DVhQ0uY0.js";
|
|
12
12
|
import "./executa-upload-binaries-D0JWYOtK.js";
|
|
13
|
-
import "./dev-
|
|
14
|
-
import "./executa-install-
|
|
13
|
+
import "./dev-uagVfV9Y.js";
|
|
14
|
+
import "./executa-install-u0nXcyy7.js";
|
|
15
15
|
import "./app-cache-Cr3tKbux.js";
|
|
16
|
-
import "./working-orchestration-
|
|
17
|
-
import "./apps-cut-
|
|
16
|
+
import "./working-orchestration-BPMFemcH.js";
|
|
17
|
+
import "./apps-cut-BLtUBokD.js";
|
|
18
18
|
import "./listing-meta-rIni8tjd.js";
|
|
19
|
-
import "./apps-push-
|
|
20
|
-
import { runAppsPublish } from "./apps-publish-
|
|
19
|
+
import "./apps-push-DZ1LHDJW.js";
|
|
20
|
+
import { runAppsPublish } from "./apps-publish-BzaoSyFn.js";
|
|
21
21
|
|
|
22
22
|
export { runAppsPublish };
|
|
@@ -2,8 +2,8 @@ import { listVersions } from "./apps-BRBufSyX.js";
|
|
|
2
2
|
import { resolveClient, withErrorHandling } from "./_lifecycle-shared-_9BzQ9Y2.js";
|
|
3
3
|
import { loadAppManifest } from "./manifest-BCHiC184.js";
|
|
4
4
|
import { bumpVersion } from "./executa-publish-BuakG1RK.js";
|
|
5
|
-
import { runAppsCut } from "./apps-cut-
|
|
6
|
-
import { runAppsPush } from "./apps-push-
|
|
5
|
+
import { runAppsCut } from "./apps-cut-BLtUBokD.js";
|
|
6
|
+
import { runAppsPush } from "./apps-push-DZ1LHDJW.js";
|
|
7
7
|
import { resolve } from "node:path";
|
|
8
8
|
import { bold, cyan, dim, green, yellow } from "kleur/colors";
|
|
9
9
|
|
|
@@ -3,7 +3,7 @@ import { CliError } from "./client-sMzq2PWG.js";
|
|
|
3
3
|
import { resolveClient, withErrorHandling } from "./_lifecycle-shared-_9BzQ9Y2.js";
|
|
4
4
|
import { loadAppManifest } from "./manifest-BCHiC184.js";
|
|
5
5
|
import { bumpVersion, bundleHash, canonicalize, manifestHash, rewriteVersion } from "./executa-publish-BuakG1RK.js";
|
|
6
|
-
import { installLocalBundledShims, resolveAppIdentity, resolveBundledExecutas } from "./working-orchestration-
|
|
6
|
+
import { installLocalBundledShims, resolveAppIdentity, resolveBundledExecutas } from "./working-orchestration-BPMFemcH.js";
|
|
7
7
|
import { syncAppListingMeta } from "./listing-meta-rIni8tjd.js";
|
|
8
8
|
import { join, relative, resolve, sep } from "node:path";
|
|
9
9
|
import { readFileSync, readdirSync, statSync } from "node:fs";
|
|
@@ -10,11 +10,11 @@ import "./executas-CvQY_w2U.js";
|
|
|
10
10
|
import "./executa-publish-BuakG1RK.js";
|
|
11
11
|
import "./binary-upload-DVhQ0uY0.js";
|
|
12
12
|
import "./executa-upload-binaries-D0JWYOtK.js";
|
|
13
|
-
import "./dev-
|
|
14
|
-
import "./executa-install-
|
|
13
|
+
import "./dev-uagVfV9Y.js";
|
|
14
|
+
import "./executa-install-u0nXcyy7.js";
|
|
15
15
|
import "./app-cache-Cr3tKbux.js";
|
|
16
|
-
import "./working-orchestration-
|
|
16
|
+
import "./working-orchestration-BPMFemcH.js";
|
|
17
17
|
import "./listing-meta-rIni8tjd.js";
|
|
18
|
-
import { runAppsPush } from "./apps-push-
|
|
18
|
+
import { runAppsPush } from "./apps-push-DZ1LHDJW.js";
|
|
19
19
|
|
|
20
20
|
export { runAppsPush };
|
|
@@ -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-
|
|
62
|
+
const { runAppsPublish } = await import("./apps-publish-AdXryRYo.js");
|
|
63
63
|
const code = await runAppsPublish({
|
|
64
64
|
cwd: opts.cwd,
|
|
65
65
|
account: opts.account,
|
package/dist/cli.js
CHANGED
|
@@ -111,18 +111,132 @@ function validateManifestSchema(bundle, manifest) {
|
|
|
111
111
|
message: `${e.message ?? "invalid"}${e.params ? " " + JSON.stringify(e.params) : ""}`
|
|
112
112
|
}));
|
|
113
113
|
}
|
|
114
|
-
|
|
114
|
+
/**
|
|
115
|
+
* Blank out string-literal and comment contents (same length, newlines
|
|
116
|
+
* kept, so offsets/line numbers stay exact). Template interpolation bodies
|
|
117
|
+
* (`${…}`) are code and are preserved. Regex literals are NOT recognised
|
|
118
|
+
* (the `/` division ambiguity): a quote delimiter inside one can at worst
|
|
119
|
+
* blank the rest of that line — quoted strings cannot span lines — which
|
|
120
|
+
* errs toward missing a call, never toward a false report.
|
|
121
|
+
*/
|
|
122
|
+
function stripStringsAndComments(source) {
|
|
123
|
+
const out = source.split("");
|
|
124
|
+
const n = source.length;
|
|
125
|
+
const blank = (idx) => {
|
|
126
|
+
const ch = out[idx];
|
|
127
|
+
if (ch !== "\n" && ch !== "\r") out[idx] = " ";
|
|
128
|
+
};
|
|
129
|
+
const stack = [{
|
|
130
|
+
kind: "code",
|
|
131
|
+
braces: 0
|
|
132
|
+
}];
|
|
133
|
+
let i = 0;
|
|
134
|
+
while (i < n) {
|
|
135
|
+
const top = stack[stack.length - 1];
|
|
136
|
+
const c = source[i];
|
|
137
|
+
if (top.kind === "tpl") {
|
|
138
|
+
if (c === "\\") {
|
|
139
|
+
blank(i);
|
|
140
|
+
if (i + 1 < n) blank(i + 1);
|
|
141
|
+
i += 2;
|
|
142
|
+
continue;
|
|
143
|
+
}
|
|
144
|
+
if (c === "`") {
|
|
145
|
+
blank(i);
|
|
146
|
+
stack.pop();
|
|
147
|
+
i++;
|
|
148
|
+
continue;
|
|
149
|
+
}
|
|
150
|
+
if (c === "$" && source[i + 1] === "{") {
|
|
151
|
+
i += 2;
|
|
152
|
+
stack.push({
|
|
153
|
+
kind: "code",
|
|
154
|
+
braces: 0
|
|
155
|
+
});
|
|
156
|
+
continue;
|
|
157
|
+
}
|
|
158
|
+
blank(i);
|
|
159
|
+
i++;
|
|
160
|
+
continue;
|
|
161
|
+
}
|
|
162
|
+
const next = source[i + 1];
|
|
163
|
+
if (c === "/" && next === "/") {
|
|
164
|
+
while (i < n && source[i] !== "\n") {
|
|
165
|
+
blank(i);
|
|
166
|
+
i++;
|
|
167
|
+
}
|
|
168
|
+
continue;
|
|
169
|
+
}
|
|
170
|
+
if (c === "/" && next === "*") {
|
|
171
|
+
blank(i);
|
|
172
|
+
blank(i + 1);
|
|
173
|
+
i += 2;
|
|
174
|
+
while (i < n && !(source[i] === "*" && source[i + 1] === "/")) {
|
|
175
|
+
blank(i);
|
|
176
|
+
i++;
|
|
177
|
+
}
|
|
178
|
+
if (i < n) {
|
|
179
|
+
blank(i);
|
|
180
|
+
blank(i + 1);
|
|
181
|
+
i += 2;
|
|
182
|
+
}
|
|
183
|
+
continue;
|
|
184
|
+
}
|
|
185
|
+
if (c === "'" || c === "\"") {
|
|
186
|
+
blank(i);
|
|
187
|
+
i++;
|
|
188
|
+
while (i < n && source[i] !== c && source[i] !== "\n") {
|
|
189
|
+
if (source[i] === "\\") {
|
|
190
|
+
blank(i);
|
|
191
|
+
i++;
|
|
192
|
+
if (i < n) blank(i);
|
|
193
|
+
i++;
|
|
194
|
+
continue;
|
|
195
|
+
}
|
|
196
|
+
blank(i);
|
|
197
|
+
i++;
|
|
198
|
+
}
|
|
199
|
+
if (i < n && source[i] === c) {
|
|
200
|
+
blank(i);
|
|
201
|
+
i++;
|
|
202
|
+
}
|
|
203
|
+
continue;
|
|
204
|
+
}
|
|
205
|
+
if (c === "`") {
|
|
206
|
+
blank(i);
|
|
207
|
+
stack.push({ kind: "tpl" });
|
|
208
|
+
i++;
|
|
209
|
+
continue;
|
|
210
|
+
}
|
|
211
|
+
if (c === "{") {
|
|
212
|
+
top.braces++;
|
|
213
|
+
i++;
|
|
214
|
+
continue;
|
|
215
|
+
}
|
|
216
|
+
if (c === "}") {
|
|
217
|
+
if (top.braces > 0) top.braces--;
|
|
218
|
+
else if (stack.length > 1) stack.pop();
|
|
219
|
+
i++;
|
|
220
|
+
continue;
|
|
221
|
+
}
|
|
222
|
+
i++;
|
|
223
|
+
}
|
|
224
|
+
return out.join("");
|
|
225
|
+
}
|
|
226
|
+
const ANNA_CALL_RE = /\banna\s*\.\s*([a-z]+)\s*\.\s*([a-zA-Z_][a-zA-Z0-9_]*)\s*\(/g;
|
|
115
227
|
function scanHostApiCalls(files) {
|
|
116
228
|
const out = [];
|
|
117
229
|
for (const f of files) {
|
|
118
|
-
const
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
230
|
+
const code = stripStringsAndComments(f.content);
|
|
231
|
+
ANNA_CALL_RE.lastIndex = 0;
|
|
232
|
+
let m;
|
|
233
|
+
let line = 1;
|
|
234
|
+
let cursor = 0;
|
|
235
|
+
while ((m = ANNA_CALL_RE.exec(code)) !== null) {
|
|
236
|
+
for (; cursor < m.index; cursor++) if (code.charCodeAt(cursor) === 10) line++;
|
|
237
|
+
out.push({
|
|
124
238
|
file: f.path,
|
|
125
|
-
line
|
|
239
|
+
line,
|
|
126
240
|
ns: m[1],
|
|
127
241
|
method: m[2]
|
|
128
242
|
});
|
|
@@ -237,7 +351,17 @@ function validateUiSectionStatic(manifest) {
|
|
|
237
351
|
const cspOverrides = ui.csp_overrides ?? {};
|
|
238
352
|
const badDirectives = Object.keys(cspOverrides).filter((d) => !CSP_OVERRIDABLE_DIRECTIVES.has(d)).sort();
|
|
239
353
|
if (badDirectives.length) errors.push(`csp_overrides 含不允许的 directive: ${JSON.stringify(badDirectives)}`);
|
|
240
|
-
for (const d of ["script-src", "style-src"])
|
|
354
|
+
for (const d of ["script-src", "style-src"]) {
|
|
355
|
+
const literals = d === "script-src" ? ["'self'", "'wasm-unsafe-eval'"] : ["'self'"];
|
|
356
|
+
for (const v of cspOverrides[d] ?? []) if (!literals.includes(v) && !v.startsWith("'sha256-") && !v.startsWith("'nonce-")) {
|
|
357
|
+
const allowed = [
|
|
358
|
+
...literals,
|
|
359
|
+
"'sha256-...'",
|
|
360
|
+
"'nonce-...'"
|
|
361
|
+
].join(" / ");
|
|
362
|
+
errors.push(`csp_overrides[${d}] 仅允许 ${allowed}: ${v}`);
|
|
363
|
+
}
|
|
364
|
+
}
|
|
241
365
|
return errors;
|
|
242
366
|
}
|
|
243
367
|
|
|
@@ -473,8 +597,8 @@ program.command("validate").description("Run schema + ACL checks on a manifest+b
|
|
|
473
597
|
const code = printResult(result);
|
|
474
598
|
process.exit(code);
|
|
475
599
|
});
|
|
476
|
-
program.command("dev").description("Run a local harness (in-process dispatcher + iframe + SSE relay)").option("--manifest <path>", "manifest.json path", "manifest.json").option("--bundle <dir>", "bundle directory (default: ./bundle)").option("--slug <slug>", "App slug (overrides manifest.slug/name)").option("--view <name>", "View name to open (default: manifest default)").option("--matrix-nexus-root <path>", "matrix-nexus checkout (auto-detected if omitted; can also use $ANNA_NEXUS_ROOT)").option("--port <number>", "HTTP port", "5180").option("--user-id <id>", "Harness user_id", "1").option("--cwd <dir>", "Project root (default: cwd)").option("--no-watch", "Disable bundle file watcher (default: enabled)").option("--executa <spec>", "Explicit executa registration; repeatable. Spec: comma-separated key=value (dir=<path>[,tool_id=<id>][,type=python|node|go|binary][,command=\"<argv>\"]). When only `dir=` is given, the executa is auto-detected from executa.json / pyproject.toml / package.json / go.mod. Overrides directory auto-discovery under <manifest-dir>/executas/.", (val, prev) => prev ? [...prev, val] : [val]).option("--no-llm", "Disable LLM bridge (anna.llm/agent return llm_disabled)").option("--mock-llm <fixture>", "Serve canned LLM responses from a JSONL fixture").option("--llm-account <host>", "Saved account host to use (default: current)").option("--llm-app-slug <slug>", "Override the manifest slug used to register / look up the dev AnnaApp (default: manifest.slug)").option("--storage <mode>", "Storage backend: \"legacy\" (in-memory runtime_state, default) or \"aps\" (real nexus APS via /api/v1/storage/* — requires `anna-app login`).", "legacy").option("--web <mode>", "Web backend: \"local\" (keyless ddgs + stdlib fetcher, free, default) or \"real\" (platform web service via /api/v1/copilot/app/web/* — production provider chain + normal CU billing; requires `anna-app login`).", "local").action(async (opts) => {
|
|
477
|
-
const { runDev, parseExecutaSpec } = await import("./dev-
|
|
600
|
+
program.command("dev").description("Run a local harness (in-process dispatcher + iframe + SSE relay)").option("--manifest <path>", "manifest.json path", "manifest.json").option("--bundle <dir>", "bundle directory (default: ./bundle)").option("--slug <slug>", "App slug (overrides manifest.slug/name)").option("--view <name>", "View name to open (default: manifest default)").option("--matrix-nexus-root <path>", "matrix-nexus checkout (auto-detected if omitted; can also use $ANNA_NEXUS_ROOT)").option("--port <number>", "HTTP port", "5180").option("--user-id <id>", "Harness user_id", "1").option("--cwd <dir>", "Project root (default: cwd)").option("--no-watch", "Disable bundle file watcher (default: enabled)").option("--executa <spec>", "Explicit executa registration; repeatable. Spec: comma-separated key=value (dir=<path>[,tool_id=<id>][,type=python|node|go|binary][,command=\"<argv>\"]). When only `dir=` is given, the executa is auto-detected from executa.json / pyproject.toml / package.json / go.mod. Overrides directory auto-discovery under <manifest-dir>/executas/.", (val, prev) => prev ? [...prev, val] : [val]).option("--no-llm", "Disable LLM bridge (anna.llm/agent return llm_disabled)").option("--mock-llm <fixture>", "Serve canned LLM responses from a JSONL fixture").option("--llm-account <host>", "Saved account host to use (default: current)").option("--llm-app-slug <slug>", "Override the manifest slug used to register / look up the dev AnnaApp (default: manifest.slug)").option("--storage <mode>", "Storage backend: \"legacy\" (in-memory runtime_state, default) or \"aps\" (real nexus APS via /api/v1/storage/* — requires `anna-app login`).", "legacy").option("--no-strict-caps", "Downgrade the production-parity storage capability gate to a warning (by default, storage/* fails with -32021 when host_capabilities declares no aps.* entry — exactly like production).").option("--web <mode>", "Web backend: \"local\" (keyless ddgs + stdlib fetcher, free, default) or \"real\" (platform web service via /api/v1/copilot/app/web/* — production provider chain + normal CU billing; requires `anna-app login`).", "local").action(async (opts) => {
|
|
601
|
+
const { runDev, parseExecutaSpec } = await import("./dev-CQIZHt7u.js");
|
|
478
602
|
const cwd = opts.cwd ?? process.cwd();
|
|
479
603
|
let executas;
|
|
480
604
|
if (opts.executa && opts.executa.length > 0) {
|
|
@@ -504,6 +628,7 @@ program.command("dev").description("Run a local harness (in-process dispatcher +
|
|
|
504
628
|
llmAccount: opts.llmAccount,
|
|
505
629
|
llmAppSlug: opts.llmAppSlug,
|
|
506
630
|
storageMode: opts.storage,
|
|
631
|
+
strictCaps: opts.strictCaps !== false,
|
|
507
632
|
webMode: opts.web
|
|
508
633
|
});
|
|
509
634
|
process.exit(code);
|
|
@@ -597,7 +722,7 @@ executa.command("register").description("Register a HARNESS AnnaApp(kind=executa
|
|
|
597
722
|
process.exit(code);
|
|
598
723
|
});
|
|
599
724
|
executa.command("install").description("Install a local-dev shim for an Executa under its minted tool_id so the Agent can discover it via 'Rediscover Local' (for distribution_type: local). Resolves the tool_id from .anna/executa.json (written by `executa publish` / `apps push`) unless --tool-id is given.").option("--dir <path>", "Executa project dir (default: CWD)").option("--tool-id <id>", "Install the shim under this exact id (default: minted id from .anna/executa.json, else executa.json tool_id)").option("--bin-dir <path>", "Install dir for the shim (default: ~/.anna/executa/bin)").option("--force", "Overwrite an existing shim of the same name", false).option("--json", "Emit machine-readable JSON", false).action(async (opts) => {
|
|
600
|
-
const { runExecutaInstall } = await import("./executa-install-
|
|
725
|
+
const { runExecutaInstall } = await import("./executa-install-Dnerah9u.js");
|
|
601
726
|
const code = await runExecutaInstall({
|
|
602
727
|
dir: opts.dir,
|
|
603
728
|
toolId: opts.toolId,
|
|
@@ -608,7 +733,7 @@ executa.command("install").description("Install a local-dev shim for an Executa
|
|
|
608
733
|
process.exit(code);
|
|
609
734
|
});
|
|
610
735
|
executa.command("dev").description("Run one Executa plugin in isolation (REPL or one-shot describe/invoke)").option("--dir <path>", "Executa project dir (default: CWD)").option("--spec <spec>", "Override discovery: comma-separated key=value (tool_id=...,type=...,command=\"...\")").option("--describe", "Print MANIFEST and exit", false).option("--health", "Print health and exit", false).option("--invoke <tool>", "Invoke one tool and exit").option("--args <json>", "JSON object passed as tool arguments", "{}").option("--json", "One-shot: emit compact JSON (no banners)", false).option("--no-sampling", "Hard-disable sampling reverse RPC (returns sampling_disabled)").option("--mock-sampling <fixture>", "Serve canned sampling responses from a JSONL fixture (offline)").option("--sampling-unsupported-format", "Simulate a model without json_schema support — exercises responseFormat onUnsupported branches (-32010 / downgrade)").option("--app-slug <slug>", "Forward sampling to nexus on behalf of this dev AnnaApp slug").option("--sampling-account <host>", "Saved account host for nexus sampling (default: current)").option("--no-agent", "Hard-disable agent reverse RPC (returns agent_not_granted)").option("--mock-agent <fixture>", "Serve canned agent/* responses from a JSONL fixture (offline)").option("--agent-account <host>", "Saved account host for nexus agent (default: --sampling-account or current)").option("--storage <mode>", "Storage backend: off | memory | mock | real (default: memory)").option("--mock-storage <fixture>", "Serve canned storage/* + files/* responses from a JSONL fixture").option("--storage-account <host>", "Saved account host for nexus storage (default: --sampling-account or current)").option("--storage-scopes <list>", "Comma-separated scopes for real storage tokens (default: user,app,tool)").option("--no-image", "Hard-disable image reverse RPC (returns image_not_granted)").option("--mock-image <fixture>", "Serve canned image/generate + image/edit responses from a JSONL fixture").option("--image-account <host>", "Saved account host for nexus image (default: --sampling-account or current)").option("--no-upload", "Hard-disable host/uploadFile reverse RPC (returns upload_not_granted)").option("--mock-upload <fixture>", "Serve canned host/uploadFile responses from a JSONL fixture").option("--upload-account <host>", "Saved account host for nexus uploads (default: --sampling-account or current)").action(async (opts) => {
|
|
611
|
-
const { runExecutaDev } = await import("./executa-dev-
|
|
736
|
+
const { runExecutaDev } = await import("./executa-dev-BeYhrj-n.js");
|
|
612
737
|
const storageMode = opts.storage === void 0 ? void 0 : (() => {
|
|
613
738
|
const m = opts.storage;
|
|
614
739
|
if (m === "off" || m === "memory" || m === "mock" || m === "real") return m;
|
|
@@ -671,7 +796,7 @@ apps.command("publish").description("Publish an Anna App version (composite: pus
|
|
|
671
796
|
console.error(`✗ --bump must be patch|minor|major (got: ${opts.bump})`);
|
|
672
797
|
process.exit(2);
|
|
673
798
|
}
|
|
674
|
-
const { runAppsPublish } = await import("./apps-publish-
|
|
799
|
+
const { runAppsPublish } = await import("./apps-publish-AdXryRYo.js");
|
|
675
800
|
process.exit(await runAppsPublish({
|
|
676
801
|
cwd: opts.cwd,
|
|
677
802
|
manifest: opts.manifest,
|
|
@@ -705,7 +830,7 @@ apps.command("push").description("Upsert the mutable working draft (manifest + b
|
|
|
705
830
|
process.exit(2);
|
|
706
831
|
}
|
|
707
832
|
}
|
|
708
|
-
const { runAppsPush } = await import("./apps-push-
|
|
833
|
+
const { runAppsPush } = await import("./apps-push-WBfD0JyE.js");
|
|
709
834
|
process.exit(await runAppsPush({
|
|
710
835
|
cwd: opts.cwd,
|
|
711
836
|
manifest: opts.manifest,
|
|
@@ -725,7 +850,7 @@ apps.command("push").description("Upsert the mutable working draft (manifest + b
|
|
|
725
850
|
}));
|
|
726
851
|
});
|
|
727
852
|
apps.command("cut <version>").description("Snapshot the working draft into an immutable version (freeze deps)").option("--changelog <text>", "Override the working draft changelog for this version").option("--slug <slug>", "App slug (default: resolve from .anna/app.json cache)").option("--cwd <dir>", "Project root for identity cache (default: cwd)").option("--dry-run", "Resolve target but don't cut", false).option("--account <host>", "Saved account host (default: current)").option("--json", "Emit machine-readable JSON", false).action(async (version, opts) => {
|
|
728
|
-
const { runAppsCut } = await import("./apps-cut-
|
|
853
|
+
const { runAppsCut } = await import("./apps-cut-eOVb1-0y.js");
|
|
729
854
|
process.exit(await runAppsCut({
|
|
730
855
|
version,
|
|
731
856
|
changelog: opts.changelog,
|
|
@@ -737,7 +862,7 @@ apps.command("cut <version>").description("Snapshot the working draft into an im
|
|
|
737
862
|
}));
|
|
738
863
|
});
|
|
739
864
|
apps.command("discard").description("Drop the mutable working draft (leaves cut versions intact)").option("--slug <slug>", "App slug (default: resolve from .anna/app.json cache)").option("--cwd <dir>", "Project root for identity cache (default: cwd)").option("--dry-run", "Resolve target but don't discard", false).option("--account <host>", "Saved account host (default: current)").option("--json", "Emit machine-readable JSON", false).action(async (opts) => {
|
|
740
|
-
const { runAppsDiscard } = await import("./apps-discard-
|
|
865
|
+
const { runAppsDiscard } = await import("./apps-discard-7ERq2pmS.js");
|
|
741
866
|
process.exit(await runAppsDiscard({
|
|
742
867
|
slug: opts.slug,
|
|
743
868
|
cwd: opts.cwd,
|
|
@@ -747,7 +872,7 @@ apps.command("discard").description("Drop the mutable working draft (leaves cut
|
|
|
747
872
|
}));
|
|
748
873
|
});
|
|
749
874
|
apps.command("release <version>").description("Freeze & publish an existing remote version (go live)").option("--slug <slug>", "App slug (default: resolve from .anna/app.json cache)").option("--cwd <dir>", "Project root for identity cache (default: cwd)").option("--allow-create", "If the version isn't on the server, run 'apps publish' first, then release", false).option("--dry-run", "Resolve target + pre-flight but don't publish", false).option("--account <host>", "Saved account host (default: current)").option("--json", "Emit machine-readable JSON", false).action(async (version, opts) => {
|
|
750
|
-
const { runAppsRelease } = await import("./apps-release-
|
|
875
|
+
const { runAppsRelease } = await import("./apps-release-DAV-DB_Q.js");
|
|
751
876
|
process.exit(await runAppsRelease({
|
|
752
877
|
version,
|
|
753
878
|
slug: opts.slug,
|
|
@@ -795,7 +920,7 @@ apps.command("versions <slug>").description("List all server versions of one Ann
|
|
|
795
920
|
}));
|
|
796
921
|
});
|
|
797
922
|
apps.command("grants <slug>").description("Show currently granted scopes/quota for one Anna App").option("--account <host>", "Saved account host (default: current)").option("--json", "Emit machine-readable JSON", false).action(async (slug, opts) => {
|
|
798
|
-
const { runAppsGrants } = await import("./apps-grants-
|
|
923
|
+
const { runAppsGrants } = await import("./apps-grants-DVoSb6-r.js");
|
|
799
924
|
process.exit(await runAppsGrants({
|
|
800
925
|
slug,
|
|
801
926
|
account: opts.account,
|
|
@@ -1001,7 +1126,7 @@ program.command("publish").description("Auto-detect cwd and publish (apps publis
|
|
|
1001
1126
|
console.error(`✗ --bump must be patch|minor|major (got: ${opts.bump})`);
|
|
1002
1127
|
process.exit(2);
|
|
1003
1128
|
}
|
|
1004
|
-
const { runTopLevelPublish } = await import("./publish-
|
|
1129
|
+
const { runTopLevelPublish } = await import("./publish-4C5_TgyZ.js");
|
|
1005
1130
|
process.exit(await runTopLevelPublish({
|
|
1006
1131
|
cwd: opts.cwd,
|
|
1007
1132
|
bump: opts.bump,
|
|
@@ -62,7 +62,7 @@ async function runDev(opts) {
|
|
|
62
62
|
process.env.ANNA_APP_RUNTIME_WEB_MODE = "real";
|
|
63
63
|
}
|
|
64
64
|
const { PythonBridge, PINNED_RUNTIME_VERSION } = await import("./bridge-nv-le8ff.js");
|
|
65
|
-
const { HarnessServer } = await import("./server-
|
|
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" ?
|
|
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,
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import "./nexus-root-BlPwOusj.js";
|
|
2
|
-
import { parseExecutaSpec } from "./dev-
|
|
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";
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { readExecutaIdentity } from "./executa-cache-BFoUtb4J.js";
|
|
2
|
-
import { parseExecutaSpec } from "./dev-
|
|
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";
|
|
@@ -10,14 +10,14 @@ import "./executas-CvQY_w2U.js";
|
|
|
10
10
|
import { runExecutaPublish } from "./executa-publish-BuakG1RK.js";
|
|
11
11
|
import "./binary-upload-DVhQ0uY0.js";
|
|
12
12
|
import "./executa-upload-binaries-D0JWYOtK.js";
|
|
13
|
-
import "./dev-
|
|
14
|
-
import "./executa-install-
|
|
13
|
+
import "./dev-uagVfV9Y.js";
|
|
14
|
+
import "./executa-install-u0nXcyy7.js";
|
|
15
15
|
import "./app-cache-Cr3tKbux.js";
|
|
16
|
-
import "./working-orchestration-
|
|
17
|
-
import "./apps-cut-
|
|
16
|
+
import "./working-orchestration-BPMFemcH.js";
|
|
17
|
+
import "./apps-cut-BLtUBokD.js";
|
|
18
18
|
import "./listing-meta-rIni8tjd.js";
|
|
19
|
-
import "./apps-push-
|
|
20
|
-
import { runAppsPublish } from "./apps-publish-
|
|
19
|
+
import "./apps-push-DZ1LHDJW.js";
|
|
20
|
+
import { runAppsPublish } from "./apps-publish-BzaoSyFn.js";
|
|
21
21
|
import { resolve } from "node:path";
|
|
22
22
|
import { existsSync } from "node:fs";
|
|
23
23
|
import { red, yellow } from "kleur/colors";
|
|
@@ -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`;
|
|
@@ -4,7 +4,7 @@ import { CliError } from "./client-sMzq2PWG.js";
|
|
|
4
4
|
import { parseExecutaIdOverrides, readExecutasLock, substituteBundledRefs, validateBundledHandles, writeBundleToolIdSidecar, writeExecutasLock } from "./bundled-executas-BRyQkI9u.js";
|
|
5
5
|
import { loadExecutaManifest } from "./manifest-BCHiC184.js";
|
|
6
6
|
import { manifestSyncNote, runExecutaPublish } from "./executa-publish-BuakG1RK.js";
|
|
7
|
-
import { runExecutaInstall } from "./executa-install-
|
|
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";
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@anna-ai/cli",
|
|
3
|
-
"version": "0.1.
|
|
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,7 +30,8 @@
|
|
|
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
|
-
"
|
|
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
37
|
"@anna-ai/app-runtime": "^0.16.0",
|
package/dist/dev-DAkNdyJ-.js
DELETED