@anna-ai/cli 0.1.22 → 0.1.23
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/{agent-Br6zY2qw.js → agent-DyXJhaZ0.js} +1 -1
- package/dist/{app-bundle-upload-DuLalcSt.js → app-bundle-upload-Cd4ci4rB.js} +1 -1
- package/dist/{apps-cut-DtEkddIk.js → apps-cut-BG6Ib3x4.js} +6 -4
- package/dist/{apps-destructive-DSTrcFUP.js → apps-destructive-DQIFqYE2.js} +1 -1
- package/dist/{apps-discard-y3_IwcbQ.js → apps-discard-BveXHAgF.js} +6 -4
- package/dist/{apps-publish-DfZTOxBJ.js → apps-publish-D403z305.js} +5 -5
- package/dist/{apps-publish-CaTCanDu.js → apps-publish-U_Y7svJw.js} +4 -4
- package/dist/{apps-push-B9XT2uwF.js → apps-push-x5reIQHx.js} +20 -6
- package/dist/{apps-release-BLH9XSxB.js → apps-release-ByIgz6lx.js} +2 -2
- package/dist/{apps-submit-review-DLwCxeAs.js → apps-submit-review-D-cPtZtc.js} +1 -1
- package/dist/{apps-sync-meta-D9eKMMUp.js → apps-sync-meta-CTHwGlzI.js} +2 -2
- package/dist/{bridge-BuklhzeE.js → bridge-CBew_Ytl.js} +1 -1
- package/dist/bridge-DZmZIWG0.js +3 -0
- package/dist/cli.js +57 -40
- package/dist/{dev-E7mqXj5S.js → dev-CyFATq6R.js} +4 -4
- package/dist/dev-DdjwQzJ2.js +3 -0
- package/dist/{doctor-DKrt-Kda.js → doctor-oqYeEjLv.js} +1 -1
- package/dist/{executa-destructive-COQE4Xqi.js → executa-destructive-Dpo58lxI.js} +1 -1
- package/dist/{executa-dev-BvS9zTpO.js → executa-dev-DFp1ckAn.js} +8 -8
- package/dist/executa-install-DnBG8UJA.js +90 -0
- package/dist/executa-install-viq3kiV7.js +6 -0
- package/dist/{executa-publish-Ca5V7MyA.js → executa-publish-BKFq6Hz9.js} +1 -1
- package/dist/{executa-publish-B88_9gbp.js → executa-publish-DaYvxbbW.js} +2 -2
- package/dist/{manifest-DGwRap2i.js → manifest-hXWnNFHE.js} +73 -14
- package/dist/{publish-C1wcf-qI.js → publish-R3JAl9Hm.js} +5 -5
- package/dist/{server-_IG8Igje.js → server-BzfmXVJD.js} +1 -1
- package/dist/{storage-CTkApNQ9.js → storage-BCj754in.js} +1 -1
- package/dist/test/index.js +3 -0
- package/dist/{working-orchestration-Dw9u1Vq0.js → working-orchestration-CIpQ_JMY.js} +51 -4
- package/package.json +1 -1
- package/templates/executa/go/main.go +4 -2
- package/templates/executa/node/plugin.mjs +4 -2
- package/templates/executa/python/__SLUG_PY___plugin.py +4 -2
- package/dist/bridge-Id8K8gr-.js +0 -3
- package/dist/dev-BS_8yoSm.js +0 -3
- /package/dist/{app-cache-BEM653Th.js → app-cache-TcmbIIuL.js} +0 -0
- /package/dist/{apps-BTn9EN0x.js → apps-B57i8xeb.js} +0 -0
- /package/dist/{apps-grants-BGWlpee0.js → apps-grants-D3i6GxX_.js} +0 -0
- /package/dist/{apps-status-DQ9RvlME.js → apps-status-BYo97Nh5.js} +0 -0
- /package/dist/{apps-versions-2Tmk0nsx.js → apps-versions-Ca-AAMLL.js} +0 -0
- /package/dist/{confirm-DxHkk9Wn.js → confirm-C-4haiIg.js} +0 -0
- /package/dist/{dev-account-qRaET1Cp.js → dev-account-CD6hTr7M.js} +0 -0
- /package/dist/{dev-app-cache-D-r6ZpEk.js → dev-app-cache-DMQLQ93-.js} +0 -0
- /package/dist/{executa-init-Jp-h9OI7.js → executa-init-By0kMPaF.js} +0 -0
- /package/dist/{executa-reads-CQ6S8gHY.js → executa-reads-cd-8ZRjI.js} +0 -0
- /package/dist/{executa-register-CulDtwYZ.js → executa-register-BX29VfcD.js} +0 -0
- /package/dist/{fixture-CYwxbiQD.js → fixture-C9VLX3os.js} +0 -0
- /package/dist/{host_upload-GXVkDM5M.js → host_upload-wKM0jQoL.js} +0 -0
- /package/dist/{image-DduR91n5.js → image-CBSlNb-9.js} +0 -0
- /package/dist/{login-BGqFjQwH.js → login-D4cU2Jcp.js} +0 -0
- /package/dist/{logout-CGIRKH3y.js → logout-DOpL3vXX.js} +0 -0
- /package/dist/{runner-B-hIqx5L.js → runner-4-ugGH5e.js} +0 -0
- /package/dist/{sampling-CXke7hq1.js → sampling-finZ8aNJ.js} +0 -0
- /package/dist/{token-B9JUPelx.js → token-BGjbb2aU.js} +0 -0
- /package/dist/{whoami-BoFLEUcp.js → whoami-DarmijoA.js} +0 -0
|
@@ -43,8 +43,8 @@ async function runDev(opts) {
|
|
|
43
43
|
}
|
|
44
44
|
process.env.ANNA_APP_RUNTIME_STORAGE_MODE = "aps";
|
|
45
45
|
}
|
|
46
|
-
const { PythonBridge, PINNED_RUNTIME_VERSION } = await import("./bridge-
|
|
47
|
-
const { HarnessServer } = await import("./server-
|
|
46
|
+
const { PythonBridge, PINNED_RUNTIME_VERSION } = await import("./bridge-DZmZIWG0.js");
|
|
47
|
+
const { HarnessServer } = await import("./server-BzfmXVJD.js");
|
|
48
48
|
const bridge = new PythonBridge({
|
|
49
49
|
mode,
|
|
50
50
|
matrixNexusRoot: matrixNexusRoot ?? void 0,
|
|
@@ -150,7 +150,7 @@ async function runDev(opts) {
|
|
|
150
150
|
*/
|
|
151
151
|
async function resolveRealLlm(args) {
|
|
152
152
|
const { getAccount } = await import("./credentials-DklPMD22.js");
|
|
153
|
-
const { ensureDevAppRegistered } = await import("./dev-app-cache-
|
|
153
|
+
const { ensureDevAppRegistered } = await import("./dev-app-cache-DMQLQ93-.js");
|
|
154
154
|
const acc = getAccount(args.account);
|
|
155
155
|
if (!acc) {
|
|
156
156
|
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.)"));
|
|
@@ -179,7 +179,7 @@ async function resolveRealLlm(args) {
|
|
|
179
179
|
account: args.account,
|
|
180
180
|
appSlug: entry.slug,
|
|
181
181
|
onAppSlugNotFound: async () => {
|
|
182
|
-
const { invalidateDevAppCache } = await import("./dev-app-cache-
|
|
182
|
+
const { invalidateDevAppCache } = await import("./dev-app-cache-DMQLQ93-.js");
|
|
183
183
|
invalidateDevAppCache(args.cwd);
|
|
184
184
|
const fresh = getAccount(args.account);
|
|
185
185
|
if (!fresh) throw new Error("PAT not found while re-registering dev app — run `anna-app login` again");
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { PINNED_RUNTIME_VERSION } from "./bridge-
|
|
1
|
+
import { PINNED_RUNTIME_VERSION } from "./bridge-CBew_Ytl.js";
|
|
2
2
|
import { dirname, isAbsolute, resolve } from "node:path";
|
|
3
3
|
import { existsSync, statSync } from "node:fs";
|
|
4
4
|
import { spawnSync } from "node:child_process";
|
|
@@ -2,7 +2,7 @@ import "./credentials-BTv2IfUZ.js";
|
|
|
2
2
|
import { CliError } from "./client-Dn9zThOd.js";
|
|
3
3
|
import { deleteMyTool, listMyTools, listToolVersions, unpublishTool, yankToolVersion } from "./executas-Cep6KEo0.js";
|
|
4
4
|
import { resolveClient, withErrorHandling } from "./_lifecycle-shared-sbea9HtH.js";
|
|
5
|
-
import { ensureDestructiveAllowed } from "./confirm-
|
|
5
|
+
import { ensureDestructiveAllowed } from "./confirm-C-4haiIg.js";
|
|
6
6
|
import { dim, green, yellow } from "kleur/colors";
|
|
7
7
|
|
|
8
8
|
//#region src/commands/executa-destructive.ts
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { parseExecutaSpec } from "./dev-
|
|
1
|
+
import { parseExecutaSpec } from "./dev-CyFATq6R.js";
|
|
2
2
|
import { isAbsolute, resolve } from "node:path";
|
|
3
3
|
import { existsSync } from "node:fs";
|
|
4
4
|
import { bold, cyan, dim, green, red, yellow } from "kleur/colors";
|
|
@@ -34,7 +34,7 @@ async function runExecutaDev(opts) {
|
|
|
34
34
|
const oneShot = !!(opts.describe || opts.health || opts.invoke);
|
|
35
35
|
const quiet = oneShot && (opts.json ?? false);
|
|
36
36
|
const { getAccount } = await import("./credentials-DklPMD22.js");
|
|
37
|
-
const { ensureDevExecutaRegistered } = await import("./dev-app-cache-
|
|
37
|
+
const { ensureDevExecutaRegistered } = await import("./dev-app-cache-DMQLQ93-.js");
|
|
38
38
|
const needsRealMint = !opts.noSampling && !opts.mockSampling || !opts.noAgent && !opts.mockAgent || !opts.noImage && !opts.mockImage || !opts.noUpload && !opts.mockUpload || opts.storage === "real";
|
|
39
39
|
let effectiveAppSlug = opts.appSlug;
|
|
40
40
|
let autoRegistered = false;
|
|
@@ -56,7 +56,7 @@ async function runExecutaDev(opts) {
|
|
|
56
56
|
}
|
|
57
57
|
}
|
|
58
58
|
}
|
|
59
|
-
const { SamplingBridge } = await import("./sampling-
|
|
59
|
+
const { SamplingBridge } = await import("./sampling-finZ8aNJ.js");
|
|
60
60
|
const sampling = opts.noSampling ? new SamplingBridge({ mode: "off" }) : opts.mockSampling ? new SamplingBridge({
|
|
61
61
|
mode: "mock",
|
|
62
62
|
mockFile: opts.mockSampling
|
|
@@ -65,7 +65,7 @@ async function runExecutaDev(opts) {
|
|
|
65
65
|
account: opts.samplingAccount,
|
|
66
66
|
appSlug: effectiveAppSlug
|
|
67
67
|
}) : new SamplingBridge({ mode: "off" });
|
|
68
|
-
const { AgentBridge } = await import("./agent-
|
|
68
|
+
const { AgentBridge } = await import("./agent-DyXJhaZ0.js");
|
|
69
69
|
const agent = opts.noAgent ? new AgentBridge({ mode: "off" }) : opts.mockAgent ? new AgentBridge({
|
|
70
70
|
mode: "mock",
|
|
71
71
|
mockFile: opts.mockAgent
|
|
@@ -74,7 +74,7 @@ async function runExecutaDev(opts) {
|
|
|
74
74
|
account: opts.agentAccount ?? opts.samplingAccount,
|
|
75
75
|
appSlug: effectiveAppSlug
|
|
76
76
|
}) : new AgentBridge({ mode: "off" });
|
|
77
|
-
const { StorageBridge } = await import("./storage-
|
|
77
|
+
const { StorageBridge } = await import("./storage-BCj754in.js");
|
|
78
78
|
const storageMode = opts.storage ?? (opts.mockStorage ? "mock" : "memory");
|
|
79
79
|
const storage = new StorageBridge({
|
|
80
80
|
mode: storageMode,
|
|
@@ -84,8 +84,8 @@ async function runExecutaDev(opts) {
|
|
|
84
84
|
scopes: opts.storageScopes ? opts.storageScopes.split(",").map((s) => s.trim()).filter(Boolean) : void 0,
|
|
85
85
|
pluginName: parsed.tool_id
|
|
86
86
|
});
|
|
87
|
-
const { ExecutaRunner } = await import("./runner-
|
|
88
|
-
const { ImageBridge } = await import("./image-
|
|
87
|
+
const { ExecutaRunner } = await import("./runner-4-ugGH5e.js");
|
|
88
|
+
const { ImageBridge } = await import("./image-CBSlNb-9.js");
|
|
89
89
|
const image = opts.noImage ? new ImageBridge({ mode: "off" }) : opts.mockImage ? new ImageBridge({
|
|
90
90
|
mode: "mock",
|
|
91
91
|
mockFile: opts.mockImage
|
|
@@ -94,7 +94,7 @@ async function runExecutaDev(opts) {
|
|
|
94
94
|
account: opts.imageAccount ?? opts.samplingAccount,
|
|
95
95
|
appSlug: effectiveAppSlug
|
|
96
96
|
}) : new ImageBridge({ mode: "off" });
|
|
97
|
-
const { HostUploadBridge } = await import("./host_upload-
|
|
97
|
+
const { HostUploadBridge } = await import("./host_upload-wKM0jQoL.js");
|
|
98
98
|
const hostUpload = opts.noUpload ? new HostUploadBridge({ mode: "off" }) : opts.mockUpload ? new HostUploadBridge({
|
|
99
99
|
mode: "mock",
|
|
100
100
|
mockFile: opts.mockUpload
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import { readExecutaIdentity } from "./executa-cache-BFoUtb4J.js";
|
|
2
|
+
import { parseExecutaSpec } from "./dev-CyFATq6R.js";
|
|
3
|
+
import { isAbsolute, join, resolve } from "node:path";
|
|
4
|
+
import { chmodSync, existsSync, mkdirSync, writeFileSync } from "node:fs";
|
|
5
|
+
import { bold, cyan, dim, green, red, yellow } from "kleur/colors";
|
|
6
|
+
import { homedir } from "node:os";
|
|
7
|
+
|
|
8
|
+
//#region src/commands/executa-install.ts
|
|
9
|
+
/** POSIX single-quote one argument for safe embedding in the shim. */
|
|
10
|
+
function shQuote(arg) {
|
|
11
|
+
return `'${arg.replace(/'/g, "'\\''")}'`;
|
|
12
|
+
}
|
|
13
|
+
function buildShim(projectDir, command) {
|
|
14
|
+
const cd = `cd ${shQuote(projectDir)} || exit 1`;
|
|
15
|
+
const exec = `exec ${command.map(shQuote).join(" ")} "$@"`;
|
|
16
|
+
return [
|
|
17
|
+
"#!/bin/sh",
|
|
18
|
+
"# Auto-generated by `anna-app executa install`.",
|
|
19
|
+
"# Local-dev launcher shim — runs the Executa from source so the Agent",
|
|
20
|
+
"# can discover it via 'Rediscover Local'. Safe to delete; regenerate",
|
|
21
|
+
"# with `anna-app executa install`.",
|
|
22
|
+
cd,
|
|
23
|
+
exec,
|
|
24
|
+
""
|
|
25
|
+
].join("\n");
|
|
26
|
+
}
|
|
27
|
+
async function runExecutaInstall(opts) {
|
|
28
|
+
const json = opts.json ?? false;
|
|
29
|
+
const cwd = opts.dir ? isAbsolute(opts.dir) ? opts.dir : resolve(process.cwd(), opts.dir) : process.cwd();
|
|
30
|
+
if (!existsSync(cwd)) {
|
|
31
|
+
console.error(red(`✗ executa dir not found: ${cwd}`));
|
|
32
|
+
return 2;
|
|
33
|
+
}
|
|
34
|
+
const parsed = parseExecutaSpec(`dir=${cwd}`, process.cwd());
|
|
35
|
+
if (parsed instanceof Error) {
|
|
36
|
+
console.error(red(`✗ ${parsed.message}`));
|
|
37
|
+
return 2;
|
|
38
|
+
}
|
|
39
|
+
if (!parsed.command || parsed.command.length === 0) {
|
|
40
|
+
console.error(red(`✗ could not derive a launch command for ${cwd}`));
|
|
41
|
+
return 2;
|
|
42
|
+
}
|
|
43
|
+
const identity = readExecutaIdentity(cwd);
|
|
44
|
+
const targetId = opts.toolId ?? identity?.tool_id ?? parsed.tool_id;
|
|
45
|
+
if (!targetId) {
|
|
46
|
+
console.error(red("✗ could not resolve a tool_id — pass --tool-id <id>, or run `anna-app executa publish` / `anna-app apps push` first to mint one."));
|
|
47
|
+
return 2;
|
|
48
|
+
}
|
|
49
|
+
if (/[/\\]/.test(targetId) || targetId.startsWith(".")) {
|
|
50
|
+
console.error(red(`✗ invalid tool_id "${targetId}" (no path separators or leading dot)`));
|
|
51
|
+
return 2;
|
|
52
|
+
}
|
|
53
|
+
const binDir = opts.binDir ? isAbsolute(opts.binDir) ? opts.binDir : resolve(process.cwd(), opts.binDir) : join(homedir(), ".anna", "executa", "bin");
|
|
54
|
+
const shimPath = join(binDir, targetId);
|
|
55
|
+
if (existsSync(shimPath) && !opts.force) {
|
|
56
|
+
console.error(red(`✗ shim already exists: ${shimPath}`) + dim(" (pass --force to overwrite)"));
|
|
57
|
+
return 1;
|
|
58
|
+
}
|
|
59
|
+
try {
|
|
60
|
+
mkdirSync(binDir, { recursive: true });
|
|
61
|
+
writeFileSync(shimPath, buildShim(parsed.project_dir, parsed.command), "utf-8");
|
|
62
|
+
chmodSync(shimPath, 493);
|
|
63
|
+
} catch (e) {
|
|
64
|
+
console.error(red(`✗ failed to write shim: ${e.message}`));
|
|
65
|
+
return 1;
|
|
66
|
+
}
|
|
67
|
+
if (json) {
|
|
68
|
+
console.log(JSON.stringify({
|
|
69
|
+
tool_id: targetId,
|
|
70
|
+
shim_path: shimPath,
|
|
71
|
+
project_dir: parsed.project_dir,
|
|
72
|
+
command: parsed.command,
|
|
73
|
+
source: opts.toolId ? "flag" : identity?.tool_id ? "identity-cache" : "discovered"
|
|
74
|
+
}));
|
|
75
|
+
return 0;
|
|
76
|
+
}
|
|
77
|
+
if (opts.quiet) return 0;
|
|
78
|
+
console.log(bold(cyan("anna-app executa install")));
|
|
79
|
+
console.log(` tool_id ${green(targetId)}`);
|
|
80
|
+
console.log(` shim ${dim(shimPath)}`);
|
|
81
|
+
console.log(` dir ${dim(parsed.project_dir)}`);
|
|
82
|
+
console.log(` command ${dim(parsed.command.join(" "))}`);
|
|
83
|
+
if (!opts.toolId && identity?.tool_id) console.log(` source ${dim("minted tool_id from .anna/executa.json")}`);
|
|
84
|
+
else if (!opts.toolId) console.log(yellow(" ! using the placeholder tool_id from executa.json — run `executa publish`/`apps push` to mint the real one, then re-run with --force (or pass --tool-id)."));
|
|
85
|
+
console.log(dim("\n→ open the Agent's Plugin Details modal and click " + bold("Rediscover Local") + dim(" to load it under this tool_id.")));
|
|
86
|
+
return 0;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
//#endregion
|
|
90
|
+
export { runExecutaInstall };
|
|
@@ -2,7 +2,7 @@ import { canonicalHost } from "./credentials-BTv2IfUZ.js";
|
|
|
2
2
|
import { CliError } from "./client-Dn9zThOd.js";
|
|
3
3
|
import { commitDraft, createDraft, getMySkill, getMyTool, listToolVersions, publishToolVersion, setSkillVisibility, setToolVisibility, updateMySkill, updateMyTool } from "./executas-Cep6KEo0.js";
|
|
4
4
|
import { executaCacheMatches, invalidateExecutaCache, mintIdempotencyKey, readExecutaIdentity, writeExecutaIdentity } from "./executa-cache-BFoUtb4J.js";
|
|
5
|
-
import { loadExecutaManifest } from "./manifest-
|
|
5
|
+
import { loadExecutaManifest } from "./manifest-hXWnNFHE.js";
|
|
6
6
|
import { resolveClient, withErrorHandling } from "./_lifecycle-shared-sbea9HtH.js";
|
|
7
7
|
import { join, relative, resolve, sep } from "node:path";
|
|
8
8
|
import { readFileSync, readdirSync, statSync, writeFileSync } from "node:fs";
|
|
@@ -2,8 +2,8 @@ import "./credentials-BTv2IfUZ.js";
|
|
|
2
2
|
import "./client-Dn9zThOd.js";
|
|
3
3
|
import "./executas-Cep6KEo0.js";
|
|
4
4
|
import "./executa-cache-BFoUtb4J.js";
|
|
5
|
-
import { runExecutaPublish } from "./executa-publish-
|
|
6
|
-
import "./manifest-
|
|
5
|
+
import { runExecutaPublish } from "./executa-publish-BKFq6Hz9.js";
|
|
6
|
+
import "./manifest-hXWnNFHE.js";
|
|
7
7
|
import "./_lifecycle-shared-sbea9HtH.js";
|
|
8
8
|
|
|
9
9
|
export { runExecutaPublish };
|
|
@@ -124,23 +124,82 @@ function loadExecutaManifest(cwd, manifestPath) {
|
|
|
124
124
|
* Returns `undefined` when absent (a dev-only Executa). Skills never carry
|
|
125
125
|
* distribution config — they are declarative Markdown, not installable
|
|
126
126
|
* processes — so a `distribution` block on a skill is rejected.
|
|
127
|
+
*
|
|
128
|
+
* Two shapes are accepted:
|
|
129
|
+
*
|
|
130
|
+
* 1. Flat (single mode) — the historical form:
|
|
131
|
+
*
|
|
132
|
+
* "distribution": { "type": "binary", "binary_urls": { … } }
|
|
133
|
+
*
|
|
134
|
+
* 2. Multi-profile (switchable) — keep several modes side by side and flip
|
|
135
|
+
* `active` to choose which one is published:
|
|
136
|
+
*
|
|
137
|
+
* "distribution": {
|
|
138
|
+
* "active": "binary",
|
|
139
|
+
* "profiles": {
|
|
140
|
+
* "local": { "type": "local", "executable_name": "…" },
|
|
141
|
+
* "binary": { "type": "binary", "binary_urls": { … } }
|
|
142
|
+
* }
|
|
143
|
+
* }
|
|
144
|
+
*
|
|
145
|
+
* Every profile is validated (so a typo in an *inactive* profile is
|
|
146
|
+
* still caught), but the returned `ExecutaDistribution` carries the
|
|
147
|
+
* fields of the *active* profile plus `active`/`profiles` for
|
|
148
|
+
* introspection. Downstream publish code stays profile-agnostic.
|
|
127
149
|
*/
|
|
128
150
|
function parseExecutaDistribution(value, executaType) {
|
|
129
151
|
if (value === void 0 || value === null) return void 0;
|
|
130
|
-
if (typeof value !== "object" || Array.isArray(value)) throw new CliError("executa.json `distribution` must be an object with a `type` field", 4);
|
|
152
|
+
if (typeof value !== "object" || Array.isArray(value)) throw new CliError("executa.json `distribution` must be an object with a `type` field (or `profiles` for the switchable multi-mode form)", 4);
|
|
131
153
|
if (executaType === "skill") throw new CliError("executa.json `distribution` is only valid for `executa_type: \"tool\"` — skills are declarative Markdown and are not installed as a process", 4);
|
|
132
154
|
const d = value;
|
|
155
|
+
if (d["profiles"] !== void 0) return parseProfiledDistribution(d);
|
|
156
|
+
return parseDistributionProfile(d, "distribution");
|
|
157
|
+
}
|
|
158
|
+
/**
|
|
159
|
+
* Resolve the multi-profile `distribution` form into the selected profile.
|
|
160
|
+
* Validates *all* profiles and records them under `profiles`.
|
|
161
|
+
*/
|
|
162
|
+
function parseProfiledDistribution(d) {
|
|
163
|
+
if (d["type"] !== void 0) throw new CliError("executa.json `distribution` cannot set both `type` (flat form) and `profiles` (switchable form) — pick one", 4);
|
|
164
|
+
const profilesRaw = d["profiles"];
|
|
165
|
+
if (profilesRaw === null || typeof profilesRaw !== "object" || Array.isArray(profilesRaw)) throw new CliError("executa.json `distribution.profiles` must be an object mapping a profile name → distribution config", 4);
|
|
166
|
+
const profileEntries = Object.entries(profilesRaw);
|
|
167
|
+
if (profileEntries.length === 0) throw new CliError("executa.json `distribution.profiles` must declare at least one profile", 4);
|
|
168
|
+
const profiles = {};
|
|
169
|
+
for (const [pname, pval] of profileEntries) {
|
|
170
|
+
if (pval === null || typeof pval !== "object" || Array.isArray(pval)) throw new CliError(`executa.json \`distribution.profiles["${pname}"]\` must be an object`, 4);
|
|
171
|
+
profiles[pname] = parseDistributionProfile(pval, `distribution.profiles["${pname}"]`);
|
|
172
|
+
}
|
|
173
|
+
const active = pickString(d, "active");
|
|
174
|
+
let selected;
|
|
175
|
+
if (active !== void 0) {
|
|
176
|
+
if (!(active in profiles)) throw new CliError(`executa.json \`distribution.active\` "${active}" is not a declared profile — expected one of ${Object.keys(profiles).join(" | ")}`, 4);
|
|
177
|
+
selected = active;
|
|
178
|
+
} else if (profileEntries.length === 1) selected = profileEntries[0][0];
|
|
179
|
+
else throw new CliError(`executa.json \`distribution.active\` is required when more than one profile is declared — expected one of ${Object.keys(profiles).join(" | ")}`, 4);
|
|
180
|
+
const resolved = profiles[selected];
|
|
181
|
+
return {
|
|
182
|
+
...resolved,
|
|
183
|
+
active: selected,
|
|
184
|
+
profiles
|
|
185
|
+
};
|
|
186
|
+
}
|
|
187
|
+
/**
|
|
188
|
+
* Parse + validate a single distribution config (one flat block or one entry
|
|
189
|
+
* of a `profiles` map). `ctx` is the JSON path label used in error messages.
|
|
190
|
+
*/
|
|
191
|
+
function parseDistributionProfile(d, ctx) {
|
|
133
192
|
const type = pickString(d, "type");
|
|
134
|
-
if (!type) throw new CliError(
|
|
135
|
-
if (!DISTRIBUTION_TYPES.has(type)) throw new CliError(`executa.json
|
|
193
|
+
if (!type) throw new CliError(`executa.json \`${ctx}.type\` is required`, 4);
|
|
194
|
+
if (!DISTRIBUTION_TYPES.has(type)) throw new CliError(`executa.json \`${ctx}.type\` "${type}" is invalid — expected one of ` + [...DISTRIBUTION_TYPES].join(" | "), 4);
|
|
136
195
|
const distType = type;
|
|
137
196
|
const packageName = pickString(d, "package_name");
|
|
138
197
|
const executableName = pickString(d, "executable_name");
|
|
139
198
|
const supportsProtocol = pickBool(d, "supports_protocol");
|
|
140
|
-
const binaryUrls = parseBinaryUrls(d["binary_urls"]);
|
|
141
|
-
const capabilities = parseCapabilities(d["capabilities"]);
|
|
142
|
-
if (PACKAGE_BACKED.has(distType) && !packageName) throw new CliError(`executa.json
|
|
143
|
-
if (distType === "binary" && (!binaryUrls || Object.keys(binaryUrls).length === 0)) throw new CliError(
|
|
199
|
+
const binaryUrls = parseBinaryUrls(d["binary_urls"], ctx);
|
|
200
|
+
const capabilities = parseCapabilities(d["capabilities"], ctx);
|
|
201
|
+
if (PACKAGE_BACKED.has(distType) && !packageName) throw new CliError(`executa.json \`${ctx}.package_name\` is required for \`${ctx}.type: "${distType}"\``, 4);
|
|
202
|
+
if (distType === "binary" && (!binaryUrls || Object.keys(binaryUrls).length === 0)) throw new CliError(`executa.json \`${ctx}.binary_urls\` is required (and non-empty) for \`${ctx}.type: "binary"\``, 4);
|
|
144
203
|
return {
|
|
145
204
|
type: distType,
|
|
146
205
|
packageName,
|
|
@@ -150,29 +209,29 @@ function parseExecutaDistribution(value, executaType) {
|
|
|
150
209
|
capabilities
|
|
151
210
|
};
|
|
152
211
|
}
|
|
153
|
-
function parseBinaryUrls(value) {
|
|
212
|
+
function parseBinaryUrls(value, ctx = "distribution") {
|
|
154
213
|
if (value === void 0 || value === null) return void 0;
|
|
155
|
-
if (typeof value !== "object" || Array.isArray(value)) throw new CliError(
|
|
214
|
+
if (typeof value !== "object" || Array.isArray(value)) throw new CliError(`executa.json \`${ctx}.binary_urls\` must be an object mapping platform → URL string or asset dict`, 4);
|
|
156
215
|
const out = {};
|
|
157
216
|
for (const [platform, asset] of Object.entries(value)) {
|
|
158
217
|
if (typeof asset === "string") {
|
|
159
|
-
if (!asset.trim()) throw new CliError(`executa.json
|
|
218
|
+
if (!asset.trim()) throw new CliError(`executa.json \`${ctx}.binary_urls["${platform}"]\` is empty`, 4);
|
|
160
219
|
out[platform] = asset;
|
|
161
220
|
continue;
|
|
162
221
|
}
|
|
163
222
|
if (asset && typeof asset === "object" && !Array.isArray(asset)) {
|
|
164
223
|
const url = pickString(asset, "url");
|
|
165
|
-
if (!url) throw new CliError(`executa.json
|
|
224
|
+
if (!url) throw new CliError(`executa.json \`${ctx}.binary_urls["${platform}"]\` asset dict missing required \`url\``, 4);
|
|
166
225
|
out[platform] = asset;
|
|
167
226
|
continue;
|
|
168
227
|
}
|
|
169
|
-
throw new CliError(`executa.json
|
|
228
|
+
throw new CliError(`executa.json \`${ctx}.binary_urls["${platform}"]\` must be a URL string or an asset dict \`{ url, sha256?, size?, entrypoint?, format? }\``, 4);
|
|
170
229
|
}
|
|
171
230
|
return out;
|
|
172
231
|
}
|
|
173
|
-
function parseCapabilities(value) {
|
|
232
|
+
function parseCapabilities(value, ctx = "distribution") {
|
|
174
233
|
if (value === void 0 || value === null) return void 0;
|
|
175
|
-
if (!Array.isArray(value) || value.some((v) => typeof v !== "string")) throw new CliError(
|
|
234
|
+
if (!Array.isArray(value) || value.some((v) => typeof v !== "string")) throw new CliError(`executa.json \`${ctx}.capabilities\` must be an array of strings`, 4);
|
|
176
235
|
return value;
|
|
177
236
|
}
|
|
178
237
|
function pickBool(o, k) {
|
|
@@ -4,12 +4,12 @@ import { CliError } from "./client-Dn9zThOd.js";
|
|
|
4
4
|
import "./bundled-executas-BNOKw4kv.js";
|
|
5
5
|
import "./executas-Cep6KEo0.js";
|
|
6
6
|
import "./executa-cache-BFoUtb4J.js";
|
|
7
|
-
import { runExecutaPublish } from "./executa-publish-
|
|
8
|
-
import "./manifest-
|
|
7
|
+
import { runExecutaPublish } from "./executa-publish-BKFq6Hz9.js";
|
|
8
|
+
import "./manifest-hXWnNFHE.js";
|
|
9
9
|
import { withErrorHandling } from "./_lifecycle-shared-sbea9HtH.js";
|
|
10
|
-
import "./app-cache-
|
|
11
|
-
import "./app-bundle-upload-
|
|
12
|
-
import { runAppsPublish } from "./apps-publish-
|
|
10
|
+
import "./app-cache-TcmbIIuL.js";
|
|
11
|
+
import "./app-bundle-upload-Cd4ci4rB.js";
|
|
12
|
+
import { runAppsPublish } from "./apps-publish-U_Y7svJw.js";
|
|
13
13
|
import { resolve } from "node:path";
|
|
14
14
|
import { existsSync } from "node:fs";
|
|
15
15
|
import { red, yellow } from "kleur/colors";
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { canonicalHost, getAccount } from "./credentials-BTv2IfUZ.js";
|
|
2
|
-
import { BridgeRequestError } from "./bridge-
|
|
2
|
+
import { BridgeRequestError } from "./bridge-CBew_Ytl.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";
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { canonicalHost } from "./credentials-BTv2IfUZ.js";
|
|
2
|
-
import { hostOf, requireAccount, withCode } from "./dev-account-
|
|
2
|
+
import { hostOf, requireAccount, withCode } from "./dev-account-CD6hTr7M.js";
|
|
3
3
|
import { resolve } from "node:path";
|
|
4
4
|
import { existsSync, readFileSync } from "node:fs";
|
|
5
5
|
|
package/dist/test/index.js
CHANGED
|
@@ -22,6 +22,9 @@ function deriveAcl(manifest) {
|
|
|
22
22
|
const bare = ref.includes(":") ? ref.split(":", 2)[1] : ref;
|
|
23
23
|
allowedTools.add(bare);
|
|
24
24
|
}
|
|
25
|
+
if (allowedTools.size === 0 && !toolsWildcard) {
|
|
26
|
+
for (const r of [...manifest.required_executas ?? [], ...manifest.optional_executas ?? []]) if (r.tool_id) allowedTools.add(r.tool_id);
|
|
27
|
+
}
|
|
25
28
|
if (allowedTools.size > 0 || toolsWildcard) allowed.add("tools.invoke");
|
|
26
29
|
for (const ns of Object.keys(NAMESPACED)) {
|
|
27
30
|
if (ns === "tools") continue;
|
|
@@ -2,10 +2,13 @@ import { canonicalHost } from "./credentials-BTv2IfUZ.js";
|
|
|
2
2
|
import { createApp, findAppBySlug, getApp } from "./apps-B1Nd8l_t.js";
|
|
3
3
|
import { CliError } from "./client-Dn9zThOd.js";
|
|
4
4
|
import { parseExecutaIdOverrides, readExecutasLock, substituteBundledRefs, validateBundledHandles, writeBundleToolIdSidecar, writeExecutasLock } from "./bundled-executas-BNOKw4kv.js";
|
|
5
|
-
import { runExecutaPublish } from "./executa-publish-
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
5
|
+
import { runExecutaPublish } from "./executa-publish-BKFq6Hz9.js";
|
|
6
|
+
import { loadExecutaManifest } from "./manifest-hXWnNFHE.js";
|
|
7
|
+
import { runExecutaInstall } from "./executa-install-DnBG8UJA.js";
|
|
8
|
+
import { appCacheMatches, readAppIdentity, writeAppIdentity } from "./app-cache-TcmbIIuL.js";
|
|
9
|
+
import { join, resolve } from "node:path";
|
|
8
10
|
import { dim, green, yellow } from "kleur/colors";
|
|
11
|
+
import { homedir } from "node:os";
|
|
9
12
|
|
|
10
13
|
//#region src/publish/working-orchestration.ts
|
|
11
14
|
async function resolveBundledExecutas(params) {
|
|
@@ -104,6 +107,50 @@ async function resolveBundledExecutas(params) {
|
|
|
104
107
|
};
|
|
105
108
|
}
|
|
106
109
|
/**
|
|
110
|
+
* Install a local-dev launcher shim for every bundled executa whose *active*
|
|
111
|
+
* distribution profile is `local`, under its minted `tool_id`. This closes
|
|
112
|
+
* the manual gap after `apps push`: a `local` executa never triggers a server
|
|
113
|
+
* `install_plugin` RPC, so the only way it turns "Running" on an Agent is the
|
|
114
|
+
* **Rediscover Local** flow — which needs an on-disk shim named exactly the
|
|
115
|
+
* minted `tool_id`. Binary/uv/npm/etc. profiles are skipped (the Agent
|
|
116
|
+
* installs those itself), as are skills (no runtime process) and dev-only
|
|
117
|
+
* executas with no distribution block.
|
|
118
|
+
*
|
|
119
|
+
* Failures are non-fatal: a shim that can't be written warns but does not
|
|
120
|
+
* fail the surrounding `apps push`.
|
|
121
|
+
*/
|
|
122
|
+
async function installLocalBundledShims(params) {
|
|
123
|
+
const { manifest, cwd, resolved, json = false } = params;
|
|
124
|
+
const binDir = params.binDir ?? join(homedir(), ".anna", "executa", "bin");
|
|
125
|
+
const installed = [];
|
|
126
|
+
for (const decl of manifest.bundledExecutas) {
|
|
127
|
+
const toolId = resolved[decl.handle];
|
|
128
|
+
if (!toolId) continue;
|
|
129
|
+
const dir = resolve(cwd, decl.path);
|
|
130
|
+
let exManifest;
|
|
131
|
+
try {
|
|
132
|
+
exManifest = loadExecutaManifest(dir);
|
|
133
|
+
} catch {
|
|
134
|
+
continue;
|
|
135
|
+
}
|
|
136
|
+
if (exManifest.distribution?.type !== "local") continue;
|
|
137
|
+
const code = await runExecutaInstall({
|
|
138
|
+
dir,
|
|
139
|
+
toolId,
|
|
140
|
+
binDir: params.binDir,
|
|
141
|
+
force: true,
|
|
142
|
+
quiet: true
|
|
143
|
+
});
|
|
144
|
+
if (code === 0) installed.push({
|
|
145
|
+
handle: decl.handle,
|
|
146
|
+
tool_id: toolId,
|
|
147
|
+
shim_path: join(binDir, toolId)
|
|
148
|
+
});
|
|
149
|
+
else if (!json) console.log(yellow(` ! could not install local dev shim for "${decl.handle}" (exit ${code})`));
|
|
150
|
+
}
|
|
151
|
+
return installed;
|
|
152
|
+
}
|
|
153
|
+
/**
|
|
107
154
|
* Resolve (creating if absent) the `AnnaApp` row, persisting the identity
|
|
108
155
|
* cache before any subsequent network call. Returns `null` only in dry-run
|
|
109
156
|
* mode when the app does not exist yet (nothing to create).
|
|
@@ -187,4 +234,4 @@ async function resolveAppBySlugOrCache(client, host, opts) {
|
|
|
187
234
|
}
|
|
188
235
|
|
|
189
236
|
//#endregion
|
|
190
|
-
export { resolveAppBySlugOrCache, resolveAppIdentity, resolveBundledExecutas };
|
|
237
|
+
export { installLocalBundledShims, resolveAppBySlugOrCache, resolveAppIdentity, resolveBundledExecutas };
|
package/package.json
CHANGED
|
@@ -33,8 +33,10 @@ type rpcError struct {
|
|
|
33
33
|
}
|
|
34
34
|
|
|
35
35
|
var (
|
|
36
|
+
// The manifest no longer declares a top-level `name`; the plugin's
|
|
37
|
+
// identity is the server-assigned tool_id (resolved from the on-disk
|
|
38
|
+
// shim name), not a self-declared manifest name.
|
|
36
39
|
manifest = map[string]any{
|
|
37
|
-
"name": "__TOOL_ID__",
|
|
38
40
|
"display_name": "__TOOL_ID__",
|
|
39
41
|
"version": "0.1.0",
|
|
40
42
|
"description": "A minimal Go Executa plugin scaffold.",
|
|
@@ -85,7 +87,7 @@ func dispatch(e envelope) {
|
|
|
85
87
|
case "initialize":
|
|
86
88
|
result = map[string]any{
|
|
87
89
|
"protocolVersion": "2.0",
|
|
88
|
-
"server_info": map[string]any{"name": manifest["
|
|
90
|
+
"server_info": map[string]any{"name": manifest["display_name"], "version": manifest["version"]},
|
|
89
91
|
"capabilities": map[string]any{"sampling": map[string]any{}},
|
|
90
92
|
}
|
|
91
93
|
case "describe":
|
|
@@ -12,7 +12,9 @@ import { randomUUID } from "node:crypto";
|
|
|
12
12
|
import process from "node:process";
|
|
13
13
|
|
|
14
14
|
const MANIFEST = {
|
|
15
|
-
name
|
|
15
|
+
// The manifest no longer declares a top-level `name`; the plugin's
|
|
16
|
+
// identity is the server-assigned tool_id (resolved from the on-disk
|
|
17
|
+
// shim name), not a self-declared manifest name.
|
|
16
18
|
display_name: "__TOOL_ID__",
|
|
17
19
|
version: "0.1.0",
|
|
18
20
|
description: "A minimal Node.js Executa plugin scaffold.",
|
|
@@ -77,7 +79,7 @@ async function dispatch(env) {
|
|
|
77
79
|
if (method === "initialize") {
|
|
78
80
|
result = {
|
|
79
81
|
protocolVersion: "2.0",
|
|
80
|
-
server_info: { name: MANIFEST.
|
|
82
|
+
server_info: { name: MANIFEST.display_name, version: MANIFEST.version },
|
|
81
83
|
capabilities: { sampling: {} },
|
|
82
84
|
};
|
|
83
85
|
} else if (method === "describe") {
|
|
@@ -18,7 +18,9 @@ import uuid
|
|
|
18
18
|
from typing import Any
|
|
19
19
|
|
|
20
20
|
MANIFEST: dict[str, Any] = {
|
|
21
|
-
|
|
21
|
+
# The manifest no longer declares a top-level `name`; the plugin's
|
|
22
|
+
# identity is the server-assigned tool_id (resolved from the on-disk
|
|
23
|
+
# shim name), not a self-declared manifest name.
|
|
22
24
|
"display_name": "__TOOL_ID__",
|
|
23
25
|
"version": "0.1.0",
|
|
24
26
|
"description": "A minimal Executa plugin scaffold.",
|
|
@@ -111,7 +113,7 @@ def _dispatch(env: dict[str, Any]) -> None:
|
|
|
111
113
|
if method == "initialize":
|
|
112
114
|
result = {
|
|
113
115
|
"protocolVersion": "2.0",
|
|
114
|
-
"server_info": {"name": MANIFEST["
|
|
116
|
+
"server_info": {"name": MANIFEST["display_name"], "version": MANIFEST["version"]},
|
|
115
117
|
"capabilities": {"sampling": {}},
|
|
116
118
|
}
|
|
117
119
|
elif method == "describe":
|
package/dist/bridge-Id8K8gr-.js
DELETED
package/dist/dev-BS_8yoSm.js
DELETED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|