@picahq/cli 1.9.0 → 1.9.2

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/index.js +75 -8
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -37,9 +37,49 @@ function writeConfig(config) {
37
37
  }
38
38
  fs.writeFileSync(CONFIG_FILE, JSON.stringify(config, null, 2), { mode: 384 });
39
39
  }
40
+ function readPicaRc() {
41
+ const rcPath = path.join(process.cwd(), ".picarc");
42
+ if (!fs.existsSync(rcPath)) return {};
43
+ try {
44
+ const content = fs.readFileSync(rcPath, "utf-8");
45
+ const result = {};
46
+ for (const line of content.split("\n")) {
47
+ const trimmed = line.trim();
48
+ if (!trimmed || trimmed.startsWith("#")) continue;
49
+ const eqIndex = trimmed.indexOf("=");
50
+ if (eqIndex === -1) continue;
51
+ const key = trimmed.slice(0, eqIndex).trim();
52
+ const value = trimmed.slice(eqIndex + 1).trim();
53
+ result[key] = value;
54
+ }
55
+ return result;
56
+ } catch {
57
+ return {};
58
+ }
59
+ }
40
60
  function getApiKey() {
41
- const config = readConfig();
42
- return config?.apiKey ?? null;
61
+ if (process.env.PICA_SECRET) return process.env.PICA_SECRET;
62
+ const rc = readPicaRc();
63
+ if (rc.PICA_SECRET) return rc.PICA_SECRET;
64
+ return readConfig()?.apiKey ?? null;
65
+ }
66
+ function getAccessControlFromAllSources() {
67
+ const rc = readPicaRc();
68
+ const fileAc = getAccessControl();
69
+ const merged = { ...fileAc };
70
+ if (rc.PICA_PERMISSIONS) {
71
+ merged.permissions = rc.PICA_PERMISSIONS;
72
+ }
73
+ if (rc.PICA_CONNECTION_KEYS) {
74
+ merged.connectionKeys = rc.PICA_CONNECTION_KEYS.split(",").map((s) => s.trim()).filter(Boolean);
75
+ }
76
+ if (rc.PICA_ACTION_IDS) {
77
+ merged.actionIds = rc.PICA_ACTION_IDS.split(",").map((s) => s.trim()).filter(Boolean);
78
+ }
79
+ if (rc.PICA_KNOWLEDGE_AGENT) {
80
+ merged.knowledgeAgent = rc.PICA_KNOWLEDGE_AGENT === "true";
81
+ }
82
+ return merged;
43
83
  }
44
84
  function getAccessControl() {
45
85
  return readConfig()?.accessControl ?? {};
@@ -1568,7 +1608,7 @@ function getConfig() {
1568
1608
  p5.cancel("Not configured. Run `pica init` first.");
1569
1609
  process.exit(1);
1570
1610
  }
1571
- const ac = getAccessControl();
1611
+ const ac = getAccessControlFromAllSources();
1572
1612
  const permissions = ac.permissions || "admin";
1573
1613
  const connectionKeys = ac.connectionKeys || ["*"];
1574
1614
  const actionIds = ac.actionIds || ["*"];
@@ -1797,7 +1837,34 @@ function colorMethod(method) {
1797
1837
  var require2 = createRequire(import.meta.url);
1798
1838
  var { version } = require2("../package.json");
1799
1839
  var program = new Command();
1800
- program.name("pica").description("CLI for managing Pica").version(version);
1840
+ program.name("pica").description(`Pica CLI \u2014 Connect AI agents to 200+ platforms through one interface.
1841
+
1842
+ Setup:
1843
+ pica init Set up API key and install MCP server
1844
+ pica add <platform> Connect a platform via OAuth (e.g. gmail, slack, shopify)
1845
+ pica config Configure access control (permissions, scoping)
1846
+
1847
+ Workflow (use these in order):
1848
+ 1. pica list List your connected platforms and connection keys
1849
+ 2. pica actions search <platform> <q> Search for actions using natural language
1850
+ 3. pica actions knowledge <plat> <id> Get full docs for an action (ALWAYS do this before execute)
1851
+ 4. pica actions execute <p> <id> <key> Execute the action
1852
+
1853
+ Example \u2014 send an email through Gmail:
1854
+ $ pica list
1855
+ # Find: gmail operational live::gmail::default::abc123
1856
+
1857
+ $ pica actions search gmail "send email" -t execute
1858
+ # Find: POST Send Email conn_mod_def::xxx::yyy
1859
+
1860
+ $ pica actions knowledge gmail conn_mod_def::xxx::yyy
1861
+ # Read the docs: required fields are to, subject, body, connectionKey
1862
+
1863
+ $ pica actions execute gmail conn_mod_def::xxx::yyy live::gmail::default::abc123 \\
1864
+ -d '{"to":"j@example.com","subject":"Hello","body":"Hi!","connectionKey":"live::gmail::default::abc123"}'
1865
+
1866
+ Platform names are always kebab-case (e.g. hub-spot, ship-station, google-calendar).
1867
+ Run 'pica platforms' to browse all 200+ available platforms.`).version(version);
1801
1868
  program.command("init").description("Set up Pica and install MCP to your AI agents").option("-y, --yes", "Skip confirmations").option("-g, --global", "Install MCP globally (available in all projects)").option("-p, --project", "Install MCP for this project only (creates .mcp.json)").action(async (options) => {
1802
1869
  await initCommand(options);
1803
1870
  });
@@ -1814,14 +1881,14 @@ connection.command("list").alias("ls").description("List your connections").acti
1814
1881
  program.command("platforms").alias("p").description("List available platforms").option("-c, --category <category>", "Filter by category").option("--json", "Output as JSON").action(async (options) => {
1815
1882
  await platformsCommand(options);
1816
1883
  });
1817
- var actions = program.command("actions").alias("a").description("Search, explore, and execute platform actions");
1818
- actions.command("search <platform> <query>").description("Search for actions on a platform").option("-t, --type <type>", "Agent type: execute or knowledge (default: knowledge)").action(async (platform, query, options) => {
1884
+ var actions = program.command("actions").alias("a").description("Search, explore, and execute platform actions (workflow: search \u2192 knowledge \u2192 execute)");
1885
+ actions.command("search <platform> <query>").description('Search for actions on a platform (e.g. pica actions search gmail "send email")').option("-t, --type <type>", "execute (to run it) or knowledge (to learn about it). Default: knowledge").action(async (platform, query, options) => {
1819
1886
  await actionsSearchCommand(platform, query, options);
1820
1887
  });
1821
- actions.command("knowledge <platform> <actionId>").alias("k").description("Get detailed documentation for an action").action(async (platform, actionId) => {
1888
+ actions.command("knowledge <platform> <actionId>").alias("k").description("Get full docs for an action \u2014 MUST call before execute to know required params").action(async (platform, actionId) => {
1822
1889
  await actionsKnowledgeCommand(platform, actionId);
1823
1890
  });
1824
- actions.command("execute <platform> <actionId> <connectionKey>").alias("x").description("Execute an action on a connected platform").option("-d, --data <json>", "Request body as JSON").option("--path-vars <json>", "Path variables as JSON").option("--query-params <json>", "Query parameters as JSON").option("--headers <json>", "Additional headers as JSON").option("--form-data", "Send as multipart/form-data").option("--form-url-encoded", "Send as application/x-www-form-urlencoded").action(async (platform, actionId, connectionKey, options) => {
1891
+ actions.command("execute <platform> <actionId> <connectionKey>").alias("x").description('Execute an action \u2014 pass connectionKey from "pica list", actionId from "actions search"').option("-d, --data <json>", "Request body as JSON").option("--path-vars <json>", "Path variables as JSON").option("--query-params <json>", "Query parameters as JSON").option("--headers <json>", "Additional headers as JSON").option("--form-data", "Send as multipart/form-data").option("--form-url-encoded", "Send as application/x-www-form-urlencoded").action(async (platform, actionId, connectionKey, options) => {
1825
1892
  await actionsExecuteCommand(platform, actionId, connectionKey, {
1826
1893
  data: options.data,
1827
1894
  pathVars: options.pathVars,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@picahq/cli",
3
- "version": "1.9.0",
3
+ "version": "1.9.2",
4
4
  "description": "CLI for managing Pica",
5
5
  "type": "module",
6
6
  "files": [