@astra-cli/cli 1.2.2 → 1.2.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/dist/astra.js +111 -17
  2. package/package.json +1 -1
package/dist/astra.js CHANGED
@@ -974,6 +974,10 @@ async function apiCall(method, path7, body, agentName, retryOpts) {
974
974
  "Content-Type": "application/json"
975
975
  };
976
976
  let baseUrl = config?.apiBase ?? "https://agents.astranova.live";
977
+ try {
978
+ baseUrl = getActiveManifest().apiBase;
979
+ } catch {
980
+ }
977
981
  if (agentName) {
978
982
  const creds = loadCredentials(agentName);
979
983
  if (creds?.api_base) {
@@ -1009,7 +1013,7 @@ async function apiCall(method, path7, body, agentName, retryOpts) {
1009
1013
  ok: false,
1010
1014
  status: 0,
1011
1015
  error: `Request to ${path7} timed out after ${timeoutMs / 1e3}s`,
1012
- hint: "The AstraNova API may be slow or unreachable. Try again."
1016
+ hint: "The API server may be slow or unreachable. Try again."
1013
1017
  };
1014
1018
  }
1015
1019
  const message = error instanceof Error ? error.message : "Unknown network error";
@@ -1829,10 +1833,10 @@ function createModelFromConfig(config) {
1829
1833
  }
1830
1834
 
1831
1835
  // src/agent/system-prompt.ts
1832
- function buildSystemPrompt(skillContext, tradingContext, walletContext, rewardsContext, onboardingContext, apiContext, profile, memoryContent) {
1836
+ function buildSystemPrompt(skillContext, tradingContext, walletContext, rewardsContext, onboardingContext, apiContext, profile, memoryContent, pluginMap) {
1833
1837
  const manifest = getActiveManifest();
1834
1838
  if (!manifest.extensions?.journeyStages) {
1835
- return buildGenericSystemPrompt(skillContext, manifest.name, manifest.description, profile, memoryContent);
1839
+ return buildGenericSystemPrompt(skillContext, manifest.name, manifest.description, profile, memoryContent, pluginMap);
1836
1840
  }
1837
1841
  const stage = profile.journeyStage ?? "full";
1838
1842
  const isPending = stage === "fresh" || stage === "pending";
@@ -1922,7 +1926,7 @@ Specific triggers to save memory:
1922
1926
  parts.push(buildJourneyGuidance(stage, profile));
1923
1927
  return parts.join("\n");
1924
1928
  }
1925
- function buildGenericSystemPrompt(skillContext, pluginName, pluginDescription, profile, memoryContent) {
1929
+ function buildGenericSystemPrompt(skillContext, pluginName, pluginDescription, profile, memoryContent, pluginMap) {
1926
1930
  const workingSpace = `~/.config/astra/spaces/${pluginName}`;
1927
1931
  const parts = [
1928
1932
  `You are an autonomous agent assistant for ${pluginName}. ${pluginDescription}`,
@@ -1974,6 +1978,38 @@ function buildGenericSystemPrompt(skillContext, pluginName, pluginDescription, p
1974
1978
  "---",
1975
1979
  ""
1976
1980
  );
1981
+ if (pluginMap?.routes && pluginMap.routes.length > 0) {
1982
+ parts.push("## Available API Routes", "");
1983
+ parts.push("Quick reference \u2014 use `api_call` with these relative paths:", "");
1984
+ parts.push("```");
1985
+ for (const r of pluginMap.routes) {
1986
+ const line = r.summary ? `${r.method.padEnd(7)} ${r.path.padEnd(45)} ${r.summary}` : `${r.method.padEnd(7)} ${r.path}`;
1987
+ parts.push(line);
1988
+ }
1989
+ parts.push("```");
1990
+ parts.push("", "---", "");
1991
+ }
1992
+ if (pluginMap?.workflows) {
1993
+ parts.push("## Workflows", "");
1994
+ for (const [name, steps] of Object.entries(pluginMap.workflows)) {
1995
+ parts.push(`**${name}:**`);
1996
+ steps.forEach((step, i) => parts.push(`${i + 1}. ${step}`));
1997
+ parts.push("");
1998
+ }
1999
+ parts.push("---", "");
2000
+ }
2001
+ if (pluginMap?.capabilities) {
2002
+ const cap = pluginMap.capabilities;
2003
+ const notes = [];
2004
+ if (cap.requiresWallet === false) notes.push("This plugin does NOT use wallets \u2014 do not suggest wallet setup.");
2005
+ if (cap.requiresVerification) notes.push("Content may require verification challenges \u2014 handle them automatically.");
2006
+ if (cap.supportsFileUpload === false) notes.push("File upload is not supported \u2014 do not attempt multipart requests.");
2007
+ if (notes.length > 0) {
2008
+ parts.push("## Plugin Notes", "");
2009
+ notes.forEach((n) => parts.push(`- ${n}`));
2010
+ parts.push("", "---", "");
2011
+ }
2012
+ }
1977
2013
  parts.push(`## ${pluginName} \u2014 Skill Documentation`, "");
1978
2014
  parts.push(sanitizedSkill);
1979
2015
  parts.push("", "---", "");
@@ -2464,7 +2500,7 @@ function resolveBody(body, rest, method) {
2464
2500
  return void 0;
2465
2501
  }
2466
2502
  var apiCallTool = tool3({
2467
- description: "Call the AstraNova Agent API. Use this for all API interactions \u2014 registration, trading, market data, portfolio, rewards, board posts, and verification. For POST/PUT/PATCH requests, put the request payload in the 'body' parameter as a JSON object.",
2503
+ description: "Call the plugin's Agent API. Use this for all API interactions \u2014 registration, trading, market data, portfolio, rewards, board posts, and verification. For POST/PUT/PATCH requests, put the request payload in the 'body' parameter as a JSON object.",
2468
2504
  parameters: apiCallSchema,
2469
2505
  execute: async (args) => {
2470
2506
  const { method, path: path7, body, ...rest } = args;
@@ -2569,7 +2605,7 @@ import fs8 from "fs";
2569
2605
  import path5 from "path";
2570
2606
  import crypto2 from "crypto";
2571
2607
  var readConfigTool = tool4({
2572
- description: "Read local AstraNova configuration or credentials. Returns public information only \u2014 private keys and API keys are never included.",
2608
+ description: "Read local agent configuration or credentials. Returns public information only \u2014 private keys and API keys are never included.",
2573
2609
  parameters: readConfigSchema,
2574
2610
  execute: async ({ key, agentName }) => {
2575
2611
  const resolvedAgent = agentName ?? getActiveAgent();
@@ -2624,7 +2660,7 @@ var readConfigTool = tool4({
2624
2660
  }
2625
2661
  });
2626
2662
  var writeConfigTool = tool4({
2627
- description: "Write local AstraNova configuration. Used to save agent credentials after registration or update profile data. Cannot write wallet files \u2014 use wallet tools instead.",
2663
+ description: "Write local agent configuration. Used to save agent credentials after registration or update profile data. Cannot write wallet files \u2014 use wallet tools instead.",
2628
2664
  parameters: writeConfigSchema,
2629
2665
  execute: async ({ agentName, data, file }) => {
2630
2666
  if (file === "credentials" && data && "secretKey" in data) {
@@ -2641,7 +2677,7 @@ var writeConfigTool = tool4({
2641
2677
  saveCredentials(agentName, {
2642
2678
  agent_name: merged.agent_name ?? agentName,
2643
2679
  api_key: merged.api_key ?? "",
2644
- api_base: merged.api_base ?? "https://agents.astranova.live"
2680
+ api_base: merged.api_base ?? getActiveManifest().apiBase
2645
2681
  });
2646
2682
  } else {
2647
2683
  const tmpPath = path5.join(dir, `.tmp-${crypto2.randomBytes(6).toString("hex")}`);
@@ -2829,7 +2865,7 @@ function stopDaemon(agentName) {
2829
2865
 
2830
2866
  // src/tools/agent-management.ts
2831
2867
  var registerAgentTool = tool6({
2832
- description: "Register a new AstraNova agent. Calls the API, saves credentials locally, and sets the new agent as active. The CLI will need to restart after this to load the new agent's context.",
2868
+ description: "Register a new agent. Calls the API, saves credentials locally, and sets the new agent as active. The CLI will need to restart after this to load the new agent's context.",
2833
2869
  parameters: registerAgentSchema,
2834
2870
  execute: async ({ name, description }) => {
2835
2871
  if (!/^[a-z0-9_-]{2,32}$/.test(name)) {
@@ -2912,7 +2948,7 @@ var switchAgentTool = tool6({
2912
2948
  }
2913
2949
  });
2914
2950
  var listAgentsTool = tool6({
2915
- description: "List all AstraNova agents registered on this machine, showing which one is active.",
2951
+ description: "List all agents registered on this machine, showing which one is active.",
2916
2952
  parameters: z6.object({}),
2917
2953
  execute: async () => {
2918
2954
  const agents = listAgents();
@@ -3369,8 +3405,8 @@ function debugLog3(msg) {
3369
3405
  if (DEBUG3) process.stderr.write(`[astra] ${msg}
3370
3406
  `);
3371
3407
  }
3372
- async function runAgentTurn(messages, skillContext, tradingContext, walletContext, rewardsContext, onboardingContext, apiContext, profile, callbacks, memoryContent) {
3373
- const systemPrompt = buildSystemPrompt(skillContext, tradingContext, walletContext, rewardsContext, onboardingContext, apiContext, profile, memoryContent);
3408
+ async function runAgentTurn(messages, skillContext, tradingContext, walletContext, rewardsContext, onboardingContext, apiContext, profile, callbacks, memoryContent, pluginMap) {
3409
+ const systemPrompt = buildSystemPrompt(skillContext, tradingContext, walletContext, rewardsContext, onboardingContext, apiContext, profile, memoryContent, pluginMap);
3374
3410
  const config = loadConfig();
3375
3411
  const provider = config?.provider ?? "openai";
3376
3412
  const systemPromptTokens = estimateTokens(systemPrompt);
@@ -4198,11 +4234,31 @@ function writeFileSecure2(filePath, data) {
4198
4234
  fs10.writeFileSync(tmpPath, data, { encoding: "utf-8", mode: 384 });
4199
4235
  fs10.renameSync(tmpPath, filePath);
4200
4236
  }
4201
- function buildPluginMap(pluginName, manifest, sections) {
4237
+ function extractRoutes(narrative) {
4238
+ const routes = [];
4239
+ const seen = /* @__PURE__ */ new Set();
4240
+ const curlPattern = /curl\s+(?:-X\s+(GET|POST|PUT|PATCH|DELETE)\s+)?["']?https?:\/\/[^/\s]+(\S+?)["']?\s/g;
4241
+ let match;
4242
+ while ((match = curlPattern.exec(narrative)) !== null) {
4243
+ const method = match[1] ?? "GET";
4244
+ const rawPath = match[2].split("?")[0].replace(/["']/g, "");
4245
+ const key = `${method} ${rawPath}`;
4246
+ if (!seen.has(key)) {
4247
+ seen.add(key);
4248
+ routes.push({ method, path: rawPath });
4249
+ }
4250
+ }
4251
+ return routes;
4252
+ }
4253
+ function buildPluginMap(pluginName, manifest, sections, skillMd) {
4202
4254
  const map = { version: 1, pluginName };
4255
+ if (manifest.description) {
4256
+ map.description = manifest.description;
4257
+ }
4203
4258
  const statusSection = sections["STATUS"];
4204
4259
  if (statusSection) {
4205
4260
  const poll = typeof statusSection.poll === "string" ? statusSection.poll.trim() : null;
4261
+ const intervalMs = typeof statusSection.intervalMs === "string" ? parseInt(statusSection.intervalMs, 10) || void 0 : void 0;
4206
4262
  const rawFields = Array.isArray(statusSection.fields) ? statusSection.fields : [];
4207
4263
  const fields = rawFields.flatMap((raw) => {
4208
4264
  const parts = raw.split("|").map((s) => s.trim());
@@ -4212,6 +4268,7 @@ function buildPluginMap(pluginName, manifest, sections) {
4212
4268
  const pollAllowed = poll && manifest.allowedPaths.some((ap) => poll.startsWith(ap));
4213
4269
  if (poll && pollAllowed && fields.length > 0) {
4214
4270
  map.status = { poll, fields };
4271
+ if (intervalMs) map.status.intervalMs = intervalMs;
4215
4272
  }
4216
4273
  }
4217
4274
  const cmdSection = sections["COMMANDS"];
@@ -4223,6 +4280,40 @@ function buildPluginMap(pluginName, manifest, sections) {
4223
4280
  return [];
4224
4281
  });
4225
4282
  }
4283
+ const routesSection = sections["ROUTES"];
4284
+ if (routesSection && Array.isArray(routesSection.routes)) {
4285
+ map.routes = routesSection.routes.flatMap((raw) => {
4286
+ const m = raw.match(/^(GET|POST|PUT|PATCH|DELETE)\s+(\S+)(?:\s{2,}(.+))?$/);
4287
+ if (m) return [{ method: m[1], path: m[2], summary: m[3]?.trim() }];
4288
+ return [];
4289
+ });
4290
+ } else {
4291
+ const narrative = extractNarrativeContent(skillMd);
4292
+ const routes = extractRoutes(narrative);
4293
+ if (routes.length > 0) map.routes = routes;
4294
+ }
4295
+ const workflowSection = sections["WORKFLOWS"];
4296
+ if (workflowSection) {
4297
+ const workflows = {};
4298
+ for (const [key, value] of Object.entries(workflowSection)) {
4299
+ if (Array.isArray(value)) {
4300
+ workflows[key] = value;
4301
+ }
4302
+ }
4303
+ if (Object.keys(workflows).length > 0) map.workflows = workflows;
4304
+ }
4305
+ const capSection = sections["CAPABILITIES"];
4306
+ if (capSection) {
4307
+ map.capabilities = {};
4308
+ if (typeof capSection.requiresWallet === "string")
4309
+ map.capabilities.requiresWallet = capSection.requiresWallet === "true";
4310
+ if (typeof capSection.requiresVerification === "string")
4311
+ map.capabilities.requiresVerification = capSection.requiresVerification === "true";
4312
+ if (typeof capSection.supportsFileUpload === "string")
4313
+ map.capabilities.supportsFileUpload = capSection.supportsFileUpload === "true";
4314
+ if (typeof capSection.authType === "string")
4315
+ map.capabilities.authType = capSection.authType;
4316
+ }
4226
4317
  return map;
4227
4318
  }
4228
4319
  function loadPluginMap(pluginName) {
@@ -4238,7 +4329,7 @@ function savePluginToDisk(manifest, skillMdContent, sections) {
4238
4329
  ensureDir(pluginDir(manifest.name));
4239
4330
  writeFileSecure2(pluginManifestPath(manifest.name), JSON.stringify(manifest, null, 2));
4240
4331
  writeFileSecure2(pluginSkillPath(manifest.name), skillMdContent);
4241
- const pluginMap = buildPluginMap(manifest.name, manifest, sections);
4332
+ const pluginMap = buildPluginMap(manifest.name, manifest, sections, skillMdContent);
4242
4333
  writeFileSecure2(pluginMapPath(manifest.name), JSON.stringify(pluginMap, null, 2));
4243
4334
  }
4244
4335
  async function addPlugin(manifestUrl) {
@@ -4445,7 +4536,8 @@ var StatusBar = React.memo(function StatusBar2({
4445
4536
  setPluginData(result.data);
4446
4537
  };
4447
4538
  void fetchPlugin();
4448
- const interval = setInterval(() => void fetchPlugin(), POLL_INTERVAL_MS);
4539
+ const pollInterval = pluginMap?.status?.intervalMs ?? POLL_INTERVAL_MS;
4540
+ const interval = setInterval(() => void fetchPlugin(), pollInterval);
4449
4541
  return () => {
4450
4542
  mountedPlugin.current = false;
4451
4543
  clearInterval(interval);
@@ -5074,7 +5166,8 @@ function App({
5074
5166
  } : () => {
5075
5167
  }
5076
5168
  },
5077
- memoryContent
5169
+ memoryContent,
5170
+ pluginMap
5078
5171
  );
5079
5172
  const baseCoreMessages = result.compactedMessages ?? newCoreMessages;
5080
5173
  const updatedCore = [...baseCoreMessages, ...result.responseMessages];
@@ -5419,7 +5512,8 @@ Let's go through it and improve or replace it.` : "I want to create a trading st
5419
5512
  setToolName(void 0);
5420
5513
  }
5421
5514
  },
5422
- memoryContent
5515
+ memoryContent,
5516
+ pluginMap
5423
5517
  );
5424
5518
  const baseCoreMessages = result.compactedMessages ?? newCoreMessages;
5425
5519
  const updatedCore = [...baseCoreMessages, ...result.responseMessages];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@astra-cli/cli",
3
- "version": "1.2.2",
3
+ "version": "1.2.3",
4
4
  "description": "The terminal for autonomous agents. Powered by AstraNova.",
5
5
  "type": "module",
6
6
  "bin": {