@picahq/cli 0.3.0 → 1.4.0
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/index.js +107 -12
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
3
|
// src/index.ts
|
|
4
|
+
import { createRequire } from "module";
|
|
4
5
|
import { Command } from "commander";
|
|
5
6
|
|
|
6
7
|
// src/commands/init.ts
|
|
@@ -371,6 +372,9 @@ async function openApiKeyPage() {
|
|
|
371
372
|
await open(getApiKeyUrl());
|
|
372
373
|
}
|
|
373
374
|
|
|
375
|
+
// src/commands/init.ts
|
|
376
|
+
import open2 from "open";
|
|
377
|
+
|
|
374
378
|
// src/lib/table.ts
|
|
375
379
|
import pc from "picocolors";
|
|
376
380
|
function printTable(columns, rows) {
|
|
@@ -409,12 +413,13 @@ function stripAnsi(str) {
|
|
|
409
413
|
|
|
410
414
|
// src/commands/init.ts
|
|
411
415
|
async function initCommand(options) {
|
|
412
|
-
p.intro(pc2.bgCyan(pc2.black(" Pica ")));
|
|
413
416
|
const existingConfig = readConfig();
|
|
414
417
|
if (existingConfig) {
|
|
418
|
+
p.intro(pc2.bgCyan(pc2.black(" Pica ")));
|
|
415
419
|
await handleExistingConfig(existingConfig.apiKey, options);
|
|
416
420
|
return;
|
|
417
421
|
}
|
|
422
|
+
printBanner();
|
|
418
423
|
await freshSetup(options);
|
|
419
424
|
}
|
|
420
425
|
async function handleExistingConfig(apiKey, options) {
|
|
@@ -772,11 +777,10 @@ ${globalPaths}
|
|
|
772
777
|
|
|
773
778
|
`;
|
|
774
779
|
}
|
|
775
|
-
summary += pc2.yellow("Note: Project config files can be committed to share with your team.\n") + pc2.yellow("Team members will need their own API key
|
|
776
|
-
${pc2.cyan("pica add gmail")} - Connect Gmail
|
|
777
|
-
${pc2.cyan("pica platforms")} - See all 200+ integrations`;
|
|
780
|
+
summary += pc2.yellow("Note: Project config files can be committed to share with your team.\n") + pc2.yellow("Team members will need their own API key.");
|
|
778
781
|
p.note(summary, "Setup Complete");
|
|
779
|
-
|
|
782
|
+
await promptConnectIntegrations(apiKey);
|
|
783
|
+
p.outro("Your AI agents now have access to Pica integrations!");
|
|
780
784
|
return;
|
|
781
785
|
}
|
|
782
786
|
const installedAgentIds = [];
|
|
@@ -793,16 +797,105 @@ ${globalPaths}
|
|
|
793
797
|
createdAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
794
798
|
});
|
|
795
799
|
p.note(
|
|
796
|
-
`Config saved to: ${pc2.dim(getConfigPath())}
|
|
797
|
-
|
|
798
|
-
Next steps:
|
|
799
|
-
${pc2.cyan("pica add gmail")} - Connect Gmail
|
|
800
|
-
${pc2.cyan("pica platforms")} - See all 200+ integrations
|
|
801
|
-
${pc2.cyan("pica connection list")} - View your connections`,
|
|
800
|
+
`Config saved to: ${pc2.dim(getConfigPath())}`,
|
|
802
801
|
"Setup Complete"
|
|
803
802
|
);
|
|
803
|
+
await promptConnectIntegrations(apiKey);
|
|
804
804
|
p.outro("Your AI agents now have access to Pica integrations!");
|
|
805
805
|
}
|
|
806
|
+
function printBanner() {
|
|
807
|
+
console.log();
|
|
808
|
+
console.log(pc2.cyan(" \u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588 \u2588\u2588\u2588\u2588\u2588\u2588 \u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588 \u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588"));
|
|
809
|
+
console.log(pc2.cyan(" \u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588 \u2588\u2588\u2588\u2588\u2588\u2588 \u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588 \u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588"));
|
|
810
|
+
console.log(pc2.cyan(" \u2588\u2588\u2588\u2588\u2588 \u2588\u2588\u2588\u2588\u2588 \u2588\u2588\u2588\u2588\u2588\u2588 \u2588\u2588\u2588\u2588\u2588 \u2588\u2588\u2588\u2588\u2588 \u2588\u2588\u2588\u2588\u2588"));
|
|
811
|
+
console.log(pc2.cyan(" \u2588\u2588\u2588\u2588\u2588 \u2588\u2588\u2588\u2588\u2588 \u2588\u2588\u2588\u2588\u2588\u2588 \u2588\u2588\u2588\u2588\u2588 \u2588\u2588\u2588\u2588\u2588 \u2588\u2588\u2588\u2588\u2588"));
|
|
812
|
+
console.log(pc2.cyan(" \u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588 \u2588\u2588\u2588\u2588\u2588\u2588 \u2588\u2588\u2588\u2588\u2588 \u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588"));
|
|
813
|
+
console.log(pc2.cyan(" \u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588 \u2588\u2588\u2588\u2588\u2588\u2588 \u2588\u2588\u2588\u2588\u2588 \u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588"));
|
|
814
|
+
console.log(pc2.cyan(" \u2588\u2588\u2588\u2588\u2588 \u2588\u2588\u2588\u2588\u2588\u2588 \u2588\u2588\u2588\u2588\u2588 \u2588\u2588\u2588\u2588\u2588 \u2588\u2588\u2588\u2588\u2588"));
|
|
815
|
+
console.log(pc2.cyan(" \u2588\u2588\u2588\u2588\u2588 \u2588\u2588\u2588\u2588\u2588\u2588 \u2588\u2588\u2588\u2588\u2588 \u2588\u2588\u2588\u2588\u2588 \u2588\u2588\u2588\u2588\u2588"));
|
|
816
|
+
console.log(pc2.cyan(" \u2588\u2588\u2588\u2588\u2588 \u2588\u2588\u2588\u2588\u2588\u2588 \u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588 \u2588\u2588\u2588\u2588\u2588 \u2588\u2588\u2588\u2588\u2588"));
|
|
817
|
+
console.log(pc2.cyan(" \u2588\u2588\u2588\u2588\u2588 \u2588\u2588\u2588\u2588\u2588\u2588 \u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588 \u2588\u2588\u2588\u2588\u2588 \u2588\u2588\u2588\u2588\u2588"));
|
|
818
|
+
console.log();
|
|
819
|
+
console.log(pc2.dim(" U N I V E R S A L I N T E G R A T I O N S F O R A I"));
|
|
820
|
+
console.log();
|
|
821
|
+
}
|
|
822
|
+
var TOP_INTEGRATIONS = [
|
|
823
|
+
{ value: "gmail", label: "Gmail", hint: "Read and send emails" },
|
|
824
|
+
{ value: "google-calendar", label: "Google Calendar", hint: "Manage events and schedules" },
|
|
825
|
+
{ value: "notion", label: "Notion", hint: "Access pages, databases, and docs" }
|
|
826
|
+
];
|
|
827
|
+
async function promptConnectIntegrations(apiKey) {
|
|
828
|
+
const api = new PicaApi(apiKey);
|
|
829
|
+
const connected = [];
|
|
830
|
+
try {
|
|
831
|
+
const existing = await api.listConnections();
|
|
832
|
+
for (const conn of existing) {
|
|
833
|
+
const match = TOP_INTEGRATIONS.find(
|
|
834
|
+
(i) => i.value === conn.platform.toLowerCase()
|
|
835
|
+
);
|
|
836
|
+
if (match) connected.push(match.value);
|
|
837
|
+
}
|
|
838
|
+
} catch {
|
|
839
|
+
}
|
|
840
|
+
let first = true;
|
|
841
|
+
while (true) {
|
|
842
|
+
const available = TOP_INTEGRATIONS.filter((i) => !connected.includes(i.value));
|
|
843
|
+
const options = [
|
|
844
|
+
...available.map((i) => ({
|
|
845
|
+
value: i.value,
|
|
846
|
+
label: i.label,
|
|
847
|
+
hint: i.hint
|
|
848
|
+
})),
|
|
849
|
+
{ value: "more", label: "Browse all 200+ platforms" },
|
|
850
|
+
{ value: "skip", label: "Skip for now", hint: "you can always run pica add later" }
|
|
851
|
+
];
|
|
852
|
+
const message = first ? "Connect your first integration?" : "Connect another?";
|
|
853
|
+
const choice = await p.select({ message, options });
|
|
854
|
+
if (p.isCancel(choice) || choice === "skip") {
|
|
855
|
+
break;
|
|
856
|
+
}
|
|
857
|
+
if (choice === "more") {
|
|
858
|
+
try {
|
|
859
|
+
await open2("https://app.picaos.com/connections");
|
|
860
|
+
p.log.info("Opened Pica dashboard in browser.");
|
|
861
|
+
} catch {
|
|
862
|
+
p.note("https://app.picaos.com/connections", "Open in browser");
|
|
863
|
+
}
|
|
864
|
+
p.log.info(`Connect from the dashboard, or use ${pc2.cyan("pica add <platform>")}`);
|
|
865
|
+
break;
|
|
866
|
+
}
|
|
867
|
+
const platform = choice;
|
|
868
|
+
const integration = TOP_INTEGRATIONS.find((i) => i.value === platform);
|
|
869
|
+
const label = integration?.label ?? platform;
|
|
870
|
+
p.log.info(`Opening browser to connect ${pc2.cyan(label)}...`);
|
|
871
|
+
try {
|
|
872
|
+
await openConnectionPage(platform);
|
|
873
|
+
} catch {
|
|
874
|
+
const url = getConnectionUrl(platform);
|
|
875
|
+
p.log.warn("Could not open browser automatically.");
|
|
876
|
+
p.note(url, "Open manually");
|
|
877
|
+
}
|
|
878
|
+
const spinner5 = p.spinner();
|
|
879
|
+
spinner5.start("Waiting for connection... (complete auth in browser)");
|
|
880
|
+
try {
|
|
881
|
+
await api.waitForConnection(platform, 5 * 60 * 1e3, 5e3);
|
|
882
|
+
spinner5.stop(`${label} connected!`);
|
|
883
|
+
p.log.success(`${pc2.green("\u2713")} ${label} is now available to your AI agents`);
|
|
884
|
+
connected.push(platform);
|
|
885
|
+
first = false;
|
|
886
|
+
} catch (error) {
|
|
887
|
+
spinner5.stop("Connection timed out");
|
|
888
|
+
if (error instanceof TimeoutError) {
|
|
889
|
+
p.log.warn(`No worries. Connect later with: ${pc2.cyan(`pica add ${platform}`)}`);
|
|
890
|
+
}
|
|
891
|
+
first = false;
|
|
892
|
+
}
|
|
893
|
+
if (TOP_INTEGRATIONS.every((i) => connected.includes(i.value))) {
|
|
894
|
+
p.log.success("All top integrations connected!");
|
|
895
|
+
break;
|
|
896
|
+
}
|
|
897
|
+
}
|
|
898
|
+
}
|
|
806
899
|
function maskApiKey(key) {
|
|
807
900
|
if (key.length <= 12) return key.slice(0, 8) + "...";
|
|
808
901
|
return key.slice(0, 8) + "..." + key.slice(-4);
|
|
@@ -1398,8 +1491,10 @@ function formatResponse(data, indent = 2) {
|
|
|
1398
1491
|
}
|
|
1399
1492
|
|
|
1400
1493
|
// src/index.ts
|
|
1494
|
+
var require2 = createRequire(import.meta.url);
|
|
1495
|
+
var { version } = require2("../package.json");
|
|
1401
1496
|
var program = new Command();
|
|
1402
|
-
program.name("pica").description("CLI for managing Pica
|
|
1497
|
+
program.name("pica").description("CLI for managing Pica").version(version);
|
|
1403
1498
|
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) => {
|
|
1404
1499
|
await initCommand(options);
|
|
1405
1500
|
});
|