@picahq/cli 1.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 +103 -11
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -372,6 +372,9 @@ async function openApiKeyPage() {
|
|
|
372
372
|
await open(getApiKeyUrl());
|
|
373
373
|
}
|
|
374
374
|
|
|
375
|
+
// src/commands/init.ts
|
|
376
|
+
import open2 from "open";
|
|
377
|
+
|
|
375
378
|
// src/lib/table.ts
|
|
376
379
|
import pc from "picocolors";
|
|
377
380
|
function printTable(columns, rows) {
|
|
@@ -410,12 +413,13 @@ function stripAnsi(str) {
|
|
|
410
413
|
|
|
411
414
|
// src/commands/init.ts
|
|
412
415
|
async function initCommand(options) {
|
|
413
|
-
p.intro(pc2.bgCyan(pc2.black(" Pica ")));
|
|
414
416
|
const existingConfig = readConfig();
|
|
415
417
|
if (existingConfig) {
|
|
418
|
+
p.intro(pc2.bgCyan(pc2.black(" Pica ")));
|
|
416
419
|
await handleExistingConfig(existingConfig.apiKey, options);
|
|
417
420
|
return;
|
|
418
421
|
}
|
|
422
|
+
printBanner();
|
|
419
423
|
await freshSetup(options);
|
|
420
424
|
}
|
|
421
425
|
async function handleExistingConfig(apiKey, options) {
|
|
@@ -773,11 +777,10 @@ ${globalPaths}
|
|
|
773
777
|
|
|
774
778
|
`;
|
|
775
779
|
}
|
|
776
|
-
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
|
|
777
|
-
${pc2.cyan("pica add gmail")} - Connect Gmail
|
|
778
|
-
${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.");
|
|
779
781
|
p.note(summary, "Setup Complete");
|
|
780
|
-
|
|
782
|
+
await promptConnectIntegrations(apiKey);
|
|
783
|
+
p.outro("Your AI agents now have access to Pica integrations!");
|
|
781
784
|
return;
|
|
782
785
|
}
|
|
783
786
|
const installedAgentIds = [];
|
|
@@ -794,16 +797,105 @@ ${globalPaths}
|
|
|
794
797
|
createdAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
795
798
|
});
|
|
796
799
|
p.note(
|
|
797
|
-
`Config saved to: ${pc2.dim(getConfigPath())}
|
|
798
|
-
|
|
799
|
-
Next steps:
|
|
800
|
-
${pc2.cyan("pica add gmail")} - Connect Gmail
|
|
801
|
-
${pc2.cyan("pica platforms")} - See all 200+ integrations
|
|
802
|
-
${pc2.cyan("pica connection list")} - View your connections`,
|
|
800
|
+
`Config saved to: ${pc2.dim(getConfigPath())}`,
|
|
803
801
|
"Setup Complete"
|
|
804
802
|
);
|
|
803
|
+
await promptConnectIntegrations(apiKey);
|
|
805
804
|
p.outro("Your AI agents now have access to Pica integrations!");
|
|
806
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
|
+
}
|
|
807
899
|
function maskApiKey(key) {
|
|
808
900
|
if (key.length <= 12) return key.slice(0, 8) + "...";
|
|
809
901
|
return key.slice(0, 8) + "..." + key.slice(-4);
|