@anna-ai/cli 0.1.11 → 0.1.12

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.
@@ -0,0 +1,44 @@
1
+ import { getAccount } from "./credentials-BTv2IfUZ.js";
2
+ import { listDevApps } from "./dev-app-cache-BMfOlTHd.js";
3
+ import { bold, cyan, dim, green, red, yellow } from "kleur/colors";
4
+
5
+ //#region src/commands/apps.ts
6
+ async function runAppsList(opts) {
7
+ const acc = getAccount(opts.account);
8
+ if (!acc) {
9
+ console.error(red("✗ no PAT on disk — run `anna-app login --host <nexus-url>` first."));
10
+ return 2;
11
+ }
12
+ let apps;
13
+ try {
14
+ apps = await listDevApps({
15
+ host: acc.host,
16
+ pat: acc.pat
17
+ });
18
+ } catch (e) {
19
+ console.error(red(`✗ ${e.message}`));
20
+ return 2;
21
+ }
22
+ if (opts.json) {
23
+ console.log(JSON.stringify({
24
+ host: acc.host,
25
+ apps
26
+ }, null, 2));
27
+ return 0;
28
+ }
29
+ console.log(bold(cyan("dev apps installed for")) + " " + cyan(acc.host));
30
+ if (apps.length === 0) {
31
+ console.log(dim(" (none — run `anna-app dev` in a project to register one)"));
32
+ return 0;
33
+ }
34
+ for (const a of apps) {
35
+ const tag = a.is_dev ? yellow("[dev]") : green("[prod]");
36
+ const enabled = a.is_enabled ? green("✓") : red("✗");
37
+ console.log(` ${tag} ${enabled} ${bold(a.slug)} ${dim(`(app_id=${a.app_id}, v=${a.installed_version})`)}`);
38
+ if (a.name && a.name !== a.slug) console.log(` ${dim(a.name)}`);
39
+ }
40
+ return 0;
41
+ }
42
+
43
+ //#endregion
44
+ export { runAppsList };
@@ -0,0 +1,3 @@
1
+ import { PINNED_RUNTIME_VERSION, PythonBridge } from "./bridge-BQUo6ehX.js";
2
+
3
+ export { PINNED_RUNTIME_VERSION, PythonBridge };
package/dist/cli.js CHANGED
@@ -444,8 +444,8 @@ program.command("validate").description("Run schema + ACL checks on a manifest+b
444
444
  const code = printResult(result);
445
445
  process.exit(code);
446
446
  });
447
- 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)", false).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-id <id>", "app_id passed to /dev/session/mint").action(async (opts) => {
448
- const { runDev, parseExecutaSpec } = await import("./dev-BPIUX2Nh.js");
447
+ 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)").action(async (opts) => {
448
+ const { runDev, parseExecutaSpec } = await import("./dev-DoY58pBM.js");
449
449
  const cwd = opts.cwd ?? process.cwd();
450
450
  let executas;
451
451
  if (opts.executa && opts.executa.length > 0) {
@@ -473,13 +473,13 @@ program.command("dev").description("Run a local harness (in-process dispatcher +
473
473
  noLlm: opts.llm === false,
474
474
  mockLlm: opts.mockLlm,
475
475
  llmAccount: opts.llmAccount,
476
- llmAppId: opts.llmAppId ? Number.parseInt(opts.llmAppId, 10) : void 0
476
+ llmAppSlug: opts.llmAppSlug
477
477
  });
478
478
  process.exit(code);
479
479
  });
480
480
  const fixture = program.command("fixture").description("Inspect / replay harness recordings (Phase 6)");
481
481
  fixture.command("verify <file>").description("Schema + invariant checks on a harness JSONL recording").option("--json", "Emit machine-readable JSON", false).action(async (file, opts) => {
482
- const { runFixtureVerify } = await import("./fixture-RceUUd84.js");
482
+ const { runFixtureVerify } = await import("./fixture-BEu4LXLG.js");
483
483
  const code = await runFixtureVerify({
484
484
  file,
485
485
  json: opts.json
@@ -487,7 +487,7 @@ fixture.command("verify <file>").description("Schema + invariant checks on a har
487
487
  process.exit(code);
488
488
  });
489
489
  fixture.command("summarize <file>").description("Print a human-readable digest of a harness recording").option("--json", "Emit machine-readable JSON", false).action(async (file, opts) => {
490
- const { runFixtureSummarize } = await import("./fixture-RceUUd84.js");
490
+ const { runFixtureSummarize } = await import("./fixture-BEu4LXLG.js");
491
491
  const code = await runFixtureSummarize({
492
492
  file,
493
493
  json: opts.json
@@ -495,7 +495,7 @@ fixture.command("summarize <file>").description("Print a human-readable digest o
495
495
  process.exit(code);
496
496
  });
497
497
  fixture.command("replay <file>").description("Dry-run replay of a harness recording (Phase 6 MVP)").option("--manifest <path>", "manifest.json path", "manifest.json").action(async (file, opts) => {
498
- const { runFixtureReplay } = await import("./fixture-RceUUd84.js");
498
+ const { runFixtureReplay } = await import("./fixture-BEu4LXLG.js");
499
499
  const code = await runFixtureReplay({
500
500
  file,
501
501
  manifest: opts.manifest
@@ -503,12 +503,12 @@ fixture.command("replay <file>").description("Dry-run replay of a harness record
503
503
  process.exit(code);
504
504
  });
505
505
  program.command("doctor").description("Check environment for `anna-app dev` (uv, matrix-nexus, dev key)").option("--matrix-nexus-root <path>", "matrix-nexus checkout (optional)").action(async (opts) => {
506
- const { runDoctor } = await import("./doctor-R1pjmBDG.js");
506
+ const { runDoctor } = await import("./doctor-DP2UB10l.js");
507
507
  const code = await runDoctor({ matrixNexusRoot: opts.matrixNexusRoot });
508
508
  process.exit(code);
509
509
  });
510
510
  program.command("login").description("Device-flow login against a nexus host; saves a PAT to ~/.config/anna/credentials.json").requiredOption("--host <url>", "nexus base URL, e.g. https://nexus.example.com").option("--no-browser", "Do not open a browser window automatically", false).action(async (opts) => {
511
- const { runLogin } = await import("./login-D8cmvBb6.js");
511
+ const { runLogin } = await import("./login-dl1Zfny8.js");
512
512
  const code = await runLogin({
513
513
  host: opts.host,
514
514
  noBrowser: opts.browser === false
@@ -516,7 +516,7 @@ program.command("login").description("Device-flow login against a nexus host; sa
516
516
  process.exit(code);
517
517
  });
518
518
  program.command("logout").description("Remove a saved PAT entry").option("--host <url>", "Account to remove (default: current)").option("--all", "Remove every saved account", false).action(async (opts) => {
519
- const { runLogout } = await import("./logout-P6L9VU4W.js");
519
+ const { runLogout } = await import("./logout-DablvlFs.js");
520
520
  const code = await runLogout({
521
521
  host: opts.host,
522
522
  all: opts.all
@@ -524,10 +524,18 @@ program.command("logout").description("Remove a saved PAT entry").option("--host
524
524
  process.exit(code);
525
525
  });
526
526
  program.command("whoami").description("Show the current account (and any others)").option("--json", "Emit machine-readable JSON", false).action(async (opts) => {
527
- const { runWhoami } = await import("./whoami-jqlQwe7Z.js");
527
+ const { runWhoami } = await import("./whoami-giXOY415.js");
528
528
  const code = await runWhoami({ json: opts.json });
529
529
  process.exit(code);
530
530
  });
531
+ program.command("apps:list").description("List dev apps installed for the current PAT").option("--account <host>", "Saved account host (default: current)").option("--json", "Emit machine-readable JSON", false).action(async (opts) => {
532
+ const { runAppsList } = await import("./apps-CDe6Fjq2.js");
533
+ const code = await runAppsList({
534
+ account: opts.account,
535
+ json: opts.json
536
+ });
537
+ process.exit(code);
538
+ });
531
539
  program.parseAsync(process.argv).catch((e) => {
532
540
  console.error(e);
533
541
  process.exit(2);
@@ -119,4 +119,4 @@ function credentialsAreLooselyPermissioned() {
119
119
  }
120
120
 
121
121
  //#endregion
122
- export { canonicalHost, credentialsAreLooselyPermissioned, getAccount, maskPat, readCredentials, removeAccount, saveAccount };
122
+ export { canonicalHost, credentialsAreLooselyPermissioned, credentialsPath, getAccount, maskPat, readCredentials, removeAccount, saveAccount, writeCredentials };
@@ -0,0 +1,3 @@
1
+ import { canonicalHost, credentialsAreLooselyPermissioned, credentialsPath, getAccount, maskPat, readCredentials, removeAccount, saveAccount, writeCredentials } from "./credentials-BTv2IfUZ.js";
2
+
3
+ export { getAccount };
@@ -337,20 +337,24 @@
337
337
  }
338
338
 
339
339
  function relayEventToIframe(ev) {
340
- // ev = { kind:"event", user_id, kind:..., payload, ts } from server.ts
340
+ // ev arrives from the WS server as { kind:"event", event:"<name>", payload }
341
+ // (see server.ts: `ws.send({ kind: "event", ...ev })`). The SDK keys its
342
+ // handlers off `event` (e.g. "rpc.stream", "auth.refresh"), so we MUST
343
+ // forward `ev.event` — not `ev.kind`, which is always the literal
344
+ // string "event" and would drop every frame on the floor.
341
345
  if (!iframe.contentWindow) return;
342
346
  const env = {
343
347
  wid: windowUuid,
344
348
  kind: "event",
345
- event: ev.kind,
349
+ event: ev.event,
346
350
  payload: ev.payload,
347
351
  };
348
352
  iframe.contentWindow.postMessage(env, "*");
349
353
  logLine(
350
354
  "event",
351
- `← event <span class="pill">${escapeHtml(ev.kind)}</span> ${escapeHtml(JSON.stringify(ev.payload))}`,
355
+ `← event <span class="pill">${escapeHtml(ev.event)}</span> ${escapeHtml(JSON.stringify(ev.payload))}`,
352
356
  );
353
- recPush("event", { event: ev.kind, payload: ev.payload });
357
+ recPush("event", { event: ev.event, payload: ev.payload });
354
358
  }
355
359
 
356
360
  // postMessage RPC bridge: iframe → POST /api/session/call → result
@@ -31,8 +31,8 @@ async function runDev(opts) {
31
31
  }
32
32
  const matrixNexusRoot = await resolveMatrixNexusRoot(opts.matrixNexusRoot, cwd);
33
33
  const mode = matrixNexusRoot ? "nexus-source" : "uvx";
34
- const { PythonBridge, PINNED_RUNTIME_VERSION } = await import("./bridge-BIO7ilgO.js");
35
- const { HarnessServer } = await import("./server-Cd5Lo-2v.js");
34
+ const { PythonBridge, PINNED_RUNTIME_VERSION } = await import("./bridge-BEHyfpPI.js");
35
+ const { HarnessServer } = await import("./server-NXmiWJjX.js");
36
36
  const bridge = new PythonBridge({
37
37
  mode,
38
38
  matrixNexusRoot: matrixNexusRoot ?? void 0,
@@ -68,12 +68,14 @@ async function runDev(opts) {
68
68
  const llm = opts.noLlm ? { mode: "off" } : opts.mockLlm ? {
69
69
  mode: "mock",
70
70
  mockFile: opts.mockLlm
71
- } : {
72
- mode: "real",
71
+ } : await resolveRealLlm({
72
+ cwd,
73
73
  account: opts.llmAccount,
74
- appId: opts.llmAppId
75
- };
76
- console.log(` llm bridge ${dim(llm.mode === "off" ? "disabled (--no-llm)" : llm.mode === "mock" ? `mock (${opts.mockLlm})` : `real${opts.llmAccount ? ` [${opts.llmAccount}]` : ""}`)}`);
74
+ appSlug: opts.llmAppSlug ?? slug,
75
+ manifest
76
+ });
77
+ if (llm === null) return 2;
78
+ 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}`)}`);
77
79
  const server = new HarnessServer({
78
80
  slug,
79
81
  manifest,
@@ -111,6 +113,49 @@ async function runDev(opts) {
111
113
  await new Promise(() => {});
112
114
  return 0;
113
115
  }
116
+ /**
117
+ * Resolve the `real` LlmBridgeOptions: load the dev PAT, register
118
+ * (or re-use) an `AnnaApp(is_dev=True)` on nexus, cache the result.
119
+ *
120
+ * Returns `null` (after printing) when registration fails so the caller
121
+ * can exit cleanly. Otherwise returns a bridge config carrying the
122
+ * registered `appSlug`.
123
+ */
124
+ async function resolveRealLlm(args) {
125
+ const { getAccount } = await import("./credentials-CIOYq2Lm.js");
126
+ const { ensureDevAppRegistered } = await import("./dev-app-cache-cXvO2XwQ.js");
127
+ const acc = getAccount(args.account);
128
+ if (!acc) {
129
+ 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.)"));
130
+ return null;
131
+ }
132
+ if (acc.expires_at && acc.expires_at < Math.floor(Date.now() / 1e3)) {
133
+ console.error(red("✗ PAT expired — run `anna-app login` again."));
134
+ return null;
135
+ }
136
+ const manifest = args.manifest;
137
+ try {
138
+ const entry = await ensureDevAppRegistered({
139
+ cwd: args.cwd,
140
+ host: acc.host,
141
+ pat: acc.pat,
142
+ input: {
143
+ slug: args.appSlug,
144
+ name: manifest.name,
145
+ category: manifest.category,
146
+ tagline: manifest.tagline
147
+ }
148
+ });
149
+ return {
150
+ mode: "real",
151
+ account: args.account,
152
+ appSlug: entry.slug
153
+ };
154
+ } catch (e) {
155
+ console.error(red(`✗ failed to register dev app on nexus: ${e.message}`));
156
+ return null;
157
+ }
158
+ }
114
159
  function deriveSlug(manifest, path) {
115
160
  const fromMan = manifest.slug ?? manifest.name;
116
161
  if (typeof fromMan === "string" && fromMan) return fromMan;
@@ -0,0 +1,93 @@
1
+ import { canonicalHost } from "./credentials-BTv2IfUZ.js";
2
+ import { dirname, join, resolve } from "node:path";
3
+ import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
4
+
5
+ //#region src/dev-app-cache.ts
6
+ const CACHE_DIR = ".anna";
7
+ const CACHE_FILE = "dev-app.json";
8
+ function cachePath(cwd) {
9
+ return resolve(cwd, CACHE_DIR, CACHE_FILE);
10
+ }
11
+ function readDevAppCache(cwd) {
12
+ const p = cachePath(cwd);
13
+ if (!existsSync(p)) return null;
14
+ try {
15
+ const raw = JSON.parse(readFileSync(p, "utf-8"));
16
+ if (typeof raw.host === "string" && typeof raw.slug === "string" && typeof raw.app_id === "number") return {
17
+ host: raw.host,
18
+ slug: raw.slug,
19
+ app_id: raw.app_id,
20
+ name: raw.name ?? raw.slug,
21
+ registered_at: raw.registered_at ?? ""
22
+ };
23
+ } catch {}
24
+ return null;
25
+ }
26
+ function writeDevAppCache(cwd, entry) {
27
+ const p = cachePath(cwd);
28
+ mkdirSync(dirname(p), { recursive: true });
29
+ writeFileSync(p, JSON.stringify(entry, null, 2) + "\n", "utf-8");
30
+ }
31
+ /** Call POST /api/v1/anna-apps/dev/apps/register. Idempotent server-side. */
32
+ async function registerDevApp(args) {
33
+ const url = `${canonicalHost(args.host)}/api/v1/anna-apps/dev/apps/register`;
34
+ const res = await fetch(url, {
35
+ method: "POST",
36
+ headers: { "content-type": "application/json" },
37
+ body: JSON.stringify({
38
+ pat: args.pat,
39
+ slug: args.input.slug,
40
+ name: args.input.name,
41
+ category: args.input.category,
42
+ tagline: args.input.tagline
43
+ })
44
+ });
45
+ if (!res.ok) {
46
+ const text = await res.text().catch(() => "");
47
+ throw new Error(`/dev/apps/register failed: HTTP ${res.status} ${text}`);
48
+ }
49
+ return await res.json();
50
+ }
51
+ /** Call GET /api/v1/anna-apps/dev/apps. */
52
+ async function listDevApps(args) {
53
+ const url = new URL(`${canonicalHost(args.host)}/api/v1/anna-apps/dev/apps`);
54
+ url.searchParams.set("pat", args.pat);
55
+ const res = await fetch(url, { method: "GET" });
56
+ if (!res.ok) {
57
+ const text = await res.text().catch(() => "");
58
+ throw new Error(`/dev/apps failed: HTTP ${res.status} ${text}`);
59
+ }
60
+ const body = await res.json();
61
+ return body.apps;
62
+ }
63
+ /**
64
+ * Convenience helper for `anna-app dev`: returns a valid cached entry if
65
+ * it still matches the manifest slug, otherwise hits the server to
66
+ * (re-)register. Throws if no PAT is available on disk.
67
+ */
68
+ async function ensureDevAppRegistered(args) {
69
+ const canonical = canonicalHost(args.host);
70
+ const cached = readDevAppCache(args.cwd);
71
+ if (cached && cached.host === canonical && cached.slug === args.input.slug) return cached;
72
+ const r = await registerDevApp({
73
+ host: args.host,
74
+ pat: args.pat,
75
+ input: args.input
76
+ });
77
+ const entry = {
78
+ host: canonical,
79
+ slug: r.slug,
80
+ app_id: r.app_id,
81
+ name: r.name,
82
+ registered_at: new Date().toISOString()
83
+ };
84
+ writeDevAppCache(args.cwd, entry);
85
+ return entry;
86
+ }
87
+ const _internal = {
88
+ cachePath,
89
+ CACHE_DIR: join(CACHE_DIR, CACHE_FILE)
90
+ };
91
+
92
+ //#endregion
93
+ export { ensureDevAppRegistered, listDevApps, readDevAppCache, registerDevApp, writeDevAppCache };
@@ -0,0 +1,4 @@
1
+ import "./credentials-BTv2IfUZ.js";
2
+ import { ensureDevAppRegistered, listDevApps, readDevAppCache, registerDevApp, writeDevAppCache } from "./dev-app-cache-BMfOlTHd.js";
3
+
4
+ export { ensureDevAppRegistered };
@@ -1,4 +1,4 @@
1
- import { PINNED_RUNTIME_VERSION } from "./bridge-Cpm3D2Wk.js";
1
+ import { PINNED_RUNTIME_VERSION } from "./bridge-BQUo6ehX.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";
@@ -1,4 +1,4 @@
1
- import { canonicalHost, saveAccount } from "./credentials-ggdaz_-7.js";
1
+ import { canonicalHost, saveAccount } from "./credentials-BTv2IfUZ.js";
2
2
 
3
3
  //#region src/commands/login.ts
4
4
  const POLL_TIMEOUT_MS = 12 * 60 * 1e3;
@@ -1,4 +1,4 @@
1
- import { canonicalHost, getAccount, readCredentials, removeAccount } from "./credentials-ggdaz_-7.js";
1
+ import { canonicalHost, getAccount, readCredentials, removeAccount } from "./credentials-BTv2IfUZ.js";
2
2
 
3
3
  //#region src/commands/logout.ts
4
4
  async function runLogout(opts) {
@@ -1,4 +1,4 @@
1
- import { canonicalHost, getAccount } from "./credentials-ggdaz_-7.js";
1
+ import { canonicalHost, getAccount } from "./credentials-BTv2IfUZ.js";
2
2
  import { dirname, join, normalize, resolve } from "node:path";
3
3
  import { createRequire } from "node:module";
4
4
  import { createReadStream, existsSync, readFileSync, statSync, watch } from "node:fs";
@@ -48,12 +48,12 @@ var LlmBridge = class {
48
48
  const cached = this.mintedAuto.get(windowUuid);
49
49
  if (cached && cached.expiresAt - 30 > Math.floor(Date.now() / 1e3)) return cached;
50
50
  const acc = this.account();
51
+ const slug = this.requireAppSlug();
51
52
  const body = {
52
53
  pat: acc.pat,
53
54
  kind: "complete",
54
- app_id: this.opts.appId ?? null
55
+ app_slug: slug
55
56
  };
56
- if (!body.app_id) body.app_id = 1;
57
57
  const minted = await this.callMint(acc.host, body);
58
58
  const ms = {
59
59
  appSessionToken: minted.app_session_token,
@@ -68,13 +68,14 @@ var LlmBridge = class {
68
68
  /** Mint a kind=agent session — called from `agent.session.create`. */
69
69
  async mintAgent(args) {
70
70
  const acc = this.account();
71
+ const slug = this.requireAppSlug();
71
72
  const submode = args.submode ?? "auto";
72
73
  const body = {
73
74
  pat: acc.pat,
74
75
  kind: "agent",
75
76
  submode,
76
77
  fixed_client_id: args.fixed_client_id ?? args.fixedClientId ?? null,
77
- app_id: this.opts.appId ?? 1,
78
+ app_slug: slug,
78
79
  label: args.label ?? "anna-app dev",
79
80
  quota_caps: args.quotaCaps ?? null
80
81
  };
@@ -89,6 +90,11 @@ var LlmBridge = class {
89
90
  this.mintedAgent.set(ms.appSessionUuid, ms);
90
91
  return ms;
91
92
  }
93
+ /** Throws a friendly error if no appSlug was wired into the bridge. */
94
+ requireAppSlug() {
95
+ if (!this.opts.appSlug) throw new Error("llm bridge has no app_slug — the harness must register the dev app via POST /api/v1/anna-apps/dev/apps/register before minting sessions. (Run `anna-app login` once, then `anna-app dev` will auto-register the manifest slug.)");
96
+ return this.opts.appSlug;
97
+ }
92
98
  async callMint(host, body) {
93
99
  const url = `${canonicalHost(host)}/api/v1/anna-apps/dev/session/mint`;
94
100
  const res = await fetch(url, {
@@ -1,4 +1,4 @@
1
- import { credentialsAreLooselyPermissioned, maskPat, readCredentials } from "./credentials-ggdaz_-7.js";
1
+ import { credentialsAreLooselyPermissioned, maskPat, readCredentials } from "./credentials-BTv2IfUZ.js";
2
2
 
3
3
  //#region src/commands/whoami.ts
4
4
  async function runWhoami(opts = {}) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@anna-ai/cli",
3
- "version": "0.1.11",
3
+ "version": "0.1.12",
4
4
  "description": "Anna App developer CLI: scaffold, validate, harness (Phase 2 MVP: init + validate).",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -32,8 +32,8 @@
32
32
  "prepublishOnly": "pnpm lint && pnpm test && pnpm build"
33
33
  },
34
34
  "dependencies": {
35
- "@anna-ai/app-runtime": "^0.1.0",
36
- "@anna-ai/app-schema": "^0.1.0",
35
+ "@anna-ai/app-runtime": "^0.2.0",
36
+ "@anna-ai/app-schema": "^0.4.0",
37
37
  "ajv": "^8.17.1",
38
38
  "ajv-formats": "^3.0.1",
39
39
  "commander": "^12.1.0",
@@ -1,3 +0,0 @@
1
- import { PINNED_RUNTIME_VERSION, PythonBridge } from "./bridge-Cpm3D2Wk.js";
2
-
3
- export { PINNED_RUNTIME_VERSION, PythonBridge };
File without changes