@piut/cli 3.4.0 → 3.5.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/cli.js +151 -37
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -141,6 +141,16 @@ async function publishServer(key) {
|
|
|
141
141
|
}
|
|
142
142
|
return res.json();
|
|
143
143
|
}
|
|
144
|
+
async function getBrain(key) {
|
|
145
|
+
const res = await fetch(`${API_BASE}/api/cli/brain`, {
|
|
146
|
+
headers: { Authorization: `Bearer ${key}` }
|
|
147
|
+
});
|
|
148
|
+
if (!res.ok) {
|
|
149
|
+
const body = await res.json().catch(() => ({ error: "Unknown error" }));
|
|
150
|
+
throw new Error(body.error || `Failed to fetch brain (HTTP ${res.status})`);
|
|
151
|
+
}
|
|
152
|
+
return res.json();
|
|
153
|
+
}
|
|
144
154
|
function getMachineId() {
|
|
145
155
|
const hostname = os.hostname();
|
|
146
156
|
return crypto.createHash("sha256").update(hostname).digest("hex").slice(0, 16);
|
|
@@ -603,19 +613,14 @@ var Spinner = class {
|
|
|
603
613
|
interval = null;
|
|
604
614
|
startTime = Date.now();
|
|
605
615
|
message = "";
|
|
606
|
-
tokens = 0;
|
|
607
616
|
sections = [];
|
|
608
617
|
start(message) {
|
|
609
618
|
this.message = message;
|
|
610
619
|
this.startTime = Date.now();
|
|
611
|
-
this.tokens = 0;
|
|
612
620
|
this.sections = [];
|
|
613
621
|
this.render();
|
|
614
622
|
this.interval = setInterval(() => this.render(), 80);
|
|
615
623
|
}
|
|
616
|
-
updateTokens(count) {
|
|
617
|
-
this.tokens = count;
|
|
618
|
-
}
|
|
619
624
|
addSection(name) {
|
|
620
625
|
this.clearLine();
|
|
621
626
|
const elapsed = this.elapsed();
|
|
@@ -639,9 +644,8 @@ var Spinner = class {
|
|
|
639
644
|
this.frame = (this.frame + 1) % SPINNER_FRAMES.length;
|
|
640
645
|
const spinner = brand(SPINNER_FRAMES[this.frame]);
|
|
641
646
|
const elapsed = dim(this.elapsed());
|
|
642
|
-
const tokenStr = this.tokens > 0 ? dim(` ${this.tokens.toLocaleString()} tokens`) : "";
|
|
643
647
|
this.clearLine();
|
|
644
|
-
process.stdout.write(` ${spinner} ${this.message} ${elapsed}
|
|
648
|
+
process.stdout.write(` ${spinner} ${this.message} ${elapsed}`);
|
|
645
649
|
}
|
|
646
650
|
elapsed() {
|
|
647
651
|
const ms = Date.now() - this.startTime;
|
|
@@ -1430,7 +1434,7 @@ async function removeCommand() {
|
|
|
1430
1434
|
}
|
|
1431
1435
|
|
|
1432
1436
|
// src/commands/build.ts
|
|
1433
|
-
import { select, checkbox as checkbox3, input } from "@inquirer/prompts";
|
|
1437
|
+
import { select, checkbox as checkbox3, input, confirm as confirm3 } from "@inquirer/prompts";
|
|
1434
1438
|
import chalk5 from "chalk";
|
|
1435
1439
|
import os6 from "os";
|
|
1436
1440
|
|
|
@@ -1578,7 +1582,6 @@ async function buildCommand(options) {
|
|
|
1578
1582
|
spinner.updateMessage(String(event.data.message || "Processing..."));
|
|
1579
1583
|
break;
|
|
1580
1584
|
case "progress":
|
|
1581
|
-
spinner.updateTokens(event.data.tokens);
|
|
1582
1585
|
break;
|
|
1583
1586
|
case "section":
|
|
1584
1587
|
spinner.addSection(String(event.data.name));
|
|
@@ -1600,28 +1603,66 @@ async function buildCommand(options) {
|
|
|
1600
1603
|
console.log();
|
|
1601
1604
|
console.log(success(" Brain built!"));
|
|
1602
1605
|
console.log();
|
|
1603
|
-
const
|
|
1604
|
-
|
|
1606
|
+
const SECTION_LABELS = {
|
|
1607
|
+
about: "About",
|
|
1608
|
+
soul: "Soul",
|
|
1609
|
+
areas: "Areas of Responsibility",
|
|
1610
|
+
projects: "Projects",
|
|
1611
|
+
memory: "Memory"
|
|
1612
|
+
};
|
|
1613
|
+
for (const [key, label] of Object.entries(SECTION_LABELS)) {
|
|
1614
|
+
const content = sections[key] || "";
|
|
1615
|
+
if (!content.trim()) {
|
|
1605
1616
|
console.log(dim(` ${label} \u2014 (empty)`));
|
|
1606
1617
|
} else {
|
|
1607
|
-
|
|
1608
|
-
const
|
|
1609
|
-
|
|
1618
|
+
console.log(success(` ${label}`));
|
|
1619
|
+
const lines = content.split("\n").filter((l) => l.trim()).slice(0, 5);
|
|
1620
|
+
for (const line of lines) {
|
|
1621
|
+
console.log(dim(` ${line.length > 80 ? line.slice(0, 80) + "..." : line}`));
|
|
1622
|
+
}
|
|
1623
|
+
const totalLines = content.split("\n").filter((l) => l.trim()).length;
|
|
1624
|
+
if (totalLines > 5) {
|
|
1625
|
+
console.log(dim(` ... (${totalLines - 5} more lines)`));
|
|
1626
|
+
}
|
|
1610
1627
|
}
|
|
1611
|
-
|
|
1612
|
-
|
|
1613
|
-
sectionSummary(sections.soul || "", "Soul");
|
|
1614
|
-
sectionSummary(sections.areas || "", "Areas of Responsibility");
|
|
1615
|
-
sectionSummary(sections.projects || "", "Projects");
|
|
1616
|
-
sectionSummary(sections.memory || "", "Memory");
|
|
1617
|
-
console.log();
|
|
1628
|
+
console.log();
|
|
1629
|
+
}
|
|
1618
1630
|
console.log(dim(` Review and edit at ${brand("piut.com/dashboard")}`));
|
|
1619
1631
|
console.log();
|
|
1632
|
+
const wantPublish = options.publish === false ? false : options.yes ? true : await confirm3({
|
|
1633
|
+
message: "Publish your brain now?",
|
|
1634
|
+
default: true
|
|
1635
|
+
});
|
|
1636
|
+
if (wantPublish) {
|
|
1637
|
+
try {
|
|
1638
|
+
await publishServer(apiKey);
|
|
1639
|
+
console.log();
|
|
1640
|
+
console.log(success(" \u2713 Brain published. MCP server is live."));
|
|
1641
|
+
console.log();
|
|
1642
|
+
} catch (err) {
|
|
1643
|
+
console.log();
|
|
1644
|
+
const msg = err.message;
|
|
1645
|
+
if (msg === "REQUIRES_SUBSCRIPTION") {
|
|
1646
|
+
console.log(chalk5.yellow(" Deploy requires an active subscription ($10/mo)."));
|
|
1647
|
+
console.log(` Subscribe at: ${brand("https://piut.com/dashboard/billing")}`);
|
|
1648
|
+
console.log(dim(" 14-day free trial included."));
|
|
1649
|
+
} else {
|
|
1650
|
+
console.log(chalk5.red(` \u2717 ${msg}`));
|
|
1651
|
+
}
|
|
1652
|
+
console.log();
|
|
1653
|
+
}
|
|
1654
|
+
} else {
|
|
1655
|
+
console.log();
|
|
1656
|
+
console.log(dim(" You can publish anytime with: ") + brand("piut deploy"));
|
|
1657
|
+
console.log();
|
|
1658
|
+
}
|
|
1620
1659
|
} catch (err) {
|
|
1621
1660
|
spinner.stop();
|
|
1622
1661
|
if (err instanceof CliError) throw err;
|
|
1623
|
-
|
|
1624
|
-
|
|
1662
|
+
const msg = err.message || "Unknown error";
|
|
1663
|
+
const hint = msg === "terminated" || msg.includes("network") || msg.includes("fetch") ? "The build was interrupted. This can happen if your scan data is very large. Try using --folders to limit which directories are scanned." : msg;
|
|
1664
|
+
console.log(chalk5.red(` \u2717 ${hint}`));
|
|
1665
|
+
throw new CliError(hint);
|
|
1625
1666
|
}
|
|
1626
1667
|
}
|
|
1627
1668
|
|
|
@@ -1808,8 +1849,10 @@ async function connectCommand(options) {
|
|
|
1808
1849
|
}
|
|
1809
1850
|
}
|
|
1810
1851
|
}
|
|
1852
|
+
const projectsWithActions = new Set(actions.map((a) => a.project.path));
|
|
1853
|
+
const alreadyConnectedCount = projects.filter((p) => !projectsWithActions.has(p.path)).length;
|
|
1811
1854
|
if (actions.length === 0) {
|
|
1812
|
-
console.log(
|
|
1855
|
+
console.log(success(` All ${projects.length} project(s) are already connected.`));
|
|
1813
1856
|
console.log();
|
|
1814
1857
|
return;
|
|
1815
1858
|
}
|
|
@@ -1820,7 +1863,10 @@ async function connectCommand(options) {
|
|
|
1820
1863
|
byProject.get(key).push(action);
|
|
1821
1864
|
}
|
|
1822
1865
|
console.log();
|
|
1823
|
-
|
|
1866
|
+
if (alreadyConnectedCount > 0) {
|
|
1867
|
+
console.log(dim(` ${alreadyConnectedCount} project(s) already connected.`));
|
|
1868
|
+
}
|
|
1869
|
+
console.log(` Found ${brand.bold(String(byProject.size))} project(s) with new connections available:`);
|
|
1824
1870
|
console.log();
|
|
1825
1871
|
const projectChoices = [];
|
|
1826
1872
|
for (const [projectPath, projectActions] of byProject) {
|
|
@@ -1831,7 +1877,8 @@ async function connectCommand(options) {
|
|
|
1831
1877
|
}).join(", ");
|
|
1832
1878
|
projectChoices.push({
|
|
1833
1879
|
name: `${projectName} ${dim(`(${desc})`)}`,
|
|
1834
|
-
value: projectPath
|
|
1880
|
+
value: projectPath,
|
|
1881
|
+
checked: true
|
|
1835
1882
|
});
|
|
1836
1883
|
}
|
|
1837
1884
|
let selectedPaths;
|
|
@@ -1903,7 +1950,7 @@ async function connectCommand(options) {
|
|
|
1903
1950
|
// src/commands/disconnect.ts
|
|
1904
1951
|
import fs10 from "fs";
|
|
1905
1952
|
import path11 from "path";
|
|
1906
|
-
import { checkbox as checkbox5, confirm as
|
|
1953
|
+
import { checkbox as checkbox5, confirm as confirm5 } from "@inquirer/prompts";
|
|
1907
1954
|
var DEDICATED_FILES = /* @__PURE__ */ new Set([
|
|
1908
1955
|
".cursor/rules/piut.mdc",
|
|
1909
1956
|
".windsurf/rules/piut.md",
|
|
@@ -2031,7 +2078,7 @@ async function disconnectCommand(options) {
|
|
|
2031
2078
|
console.log(dim(" No projects selected."));
|
|
2032
2079
|
return;
|
|
2033
2080
|
}
|
|
2034
|
-
const proceed = await
|
|
2081
|
+
const proceed = await confirm5({
|
|
2035
2082
|
message: `Disconnect ${selectedPaths.length} project(s)?`,
|
|
2036
2083
|
default: false
|
|
2037
2084
|
});
|
|
@@ -2110,7 +2157,7 @@ import chalk8 from "chalk";
|
|
|
2110
2157
|
// src/lib/update-check.ts
|
|
2111
2158
|
import { execFile } from "child_process";
|
|
2112
2159
|
import chalk7 from "chalk";
|
|
2113
|
-
import { confirm as
|
|
2160
|
+
import { confirm as confirm6 } from "@inquirer/prompts";
|
|
2114
2161
|
var PACKAGE_NAME = "@piut/cli";
|
|
2115
2162
|
function isNpx() {
|
|
2116
2163
|
return process.env.npm_command === "exec" || (process.env._?.includes("npx") ?? false);
|
|
@@ -2150,7 +2197,7 @@ async function checkForUpdate(currentVersion) {
|
|
|
2150
2197
|
console.log();
|
|
2151
2198
|
if (npx) return;
|
|
2152
2199
|
try {
|
|
2153
|
-
const shouldUpdate = await
|
|
2200
|
+
const shouldUpdate = await confirm6({
|
|
2154
2201
|
message: `Update to v${latest} now?`,
|
|
2155
2202
|
default: true
|
|
2156
2203
|
});
|
|
@@ -2374,7 +2421,7 @@ async function doctorCommand(options) {
|
|
|
2374
2421
|
}
|
|
2375
2422
|
|
|
2376
2423
|
// src/commands/interactive.ts
|
|
2377
|
-
import { select as select2, confirm as
|
|
2424
|
+
import { select as select2, confirm as confirm7, checkbox as checkbox6, password as password3 } from "@inquirer/prompts";
|
|
2378
2425
|
import fs12 from "fs";
|
|
2379
2426
|
import path12 from "path";
|
|
2380
2427
|
import chalk10 from "chalk";
|
|
@@ -2428,7 +2475,7 @@ async function interactiveMenu() {
|
|
|
2428
2475
|
console.log(warning(" You haven\u2019t built a brain yet."));
|
|
2429
2476
|
console.log(dim(" Your brain is how AI tools learn about you \u2014 your projects, preferences, and context."));
|
|
2430
2477
|
console.log();
|
|
2431
|
-
const wantBuild = await
|
|
2478
|
+
const wantBuild = await confirm7({
|
|
2432
2479
|
message: "Build your brain now?",
|
|
2433
2480
|
default: true
|
|
2434
2481
|
});
|
|
@@ -2444,7 +2491,7 @@ async function interactiveMenu() {
|
|
|
2444
2491
|
console.log(warning(" Your brain is built but not deployed yet."));
|
|
2445
2492
|
console.log(dim(" Deploy it to make your MCP server live so AI tools can read your brain."));
|
|
2446
2493
|
console.log();
|
|
2447
|
-
const wantDeploy = await
|
|
2494
|
+
const wantDeploy = await confirm7({
|
|
2448
2495
|
message: "Deploy your brain now?",
|
|
2449
2496
|
default: true
|
|
2450
2497
|
});
|
|
@@ -2498,6 +2545,12 @@ async function interactiveMenu() {
|
|
|
2498
2545
|
description: "Remove brain references from project configs",
|
|
2499
2546
|
disabled: !isDeployed && "(deploy brain first)"
|
|
2500
2547
|
},
|
|
2548
|
+
{
|
|
2549
|
+
name: "View Brain",
|
|
2550
|
+
value: "view-brain",
|
|
2551
|
+
description: "View all 5 brain sections",
|
|
2552
|
+
disabled: !hasBrain && "(build brain first)"
|
|
2553
|
+
},
|
|
2501
2554
|
{
|
|
2502
2555
|
name: "Status",
|
|
2503
2556
|
value: "status",
|
|
@@ -2543,6 +2596,9 @@ async function interactiveMenu() {
|
|
|
2543
2596
|
case "disconnect-projects":
|
|
2544
2597
|
await disconnectCommand({});
|
|
2545
2598
|
break;
|
|
2599
|
+
case "view-brain":
|
|
2600
|
+
await handleViewBrain(apiKey);
|
|
2601
|
+
break;
|
|
2546
2602
|
case "status":
|
|
2547
2603
|
statusCommand();
|
|
2548
2604
|
break;
|
|
@@ -2575,7 +2631,7 @@ async function interactiveMenu() {
|
|
|
2575
2631
|
}
|
|
2576
2632
|
}
|
|
2577
2633
|
async function handleUndeploy(apiKey) {
|
|
2578
|
-
const confirmed = await
|
|
2634
|
+
const confirmed = await confirm7({
|
|
2579
2635
|
message: "Undeploy your brain? AI tools will lose access to your MCP server.",
|
|
2580
2636
|
default: false
|
|
2581
2637
|
});
|
|
@@ -2642,6 +2698,11 @@ async function handleConnectTools(apiKey, validation) {
|
|
|
2642
2698
|
mergeConfig(configPath, tool.configKey, serverConfig);
|
|
2643
2699
|
toolLine(tool.name, success("connected"), "\u2714");
|
|
2644
2700
|
}
|
|
2701
|
+
if (validation.serverUrl) {
|
|
2702
|
+
await Promise.all(
|
|
2703
|
+
selected.map(({ tool }) => pingMcp(validation.serverUrl, apiKey, tool.name))
|
|
2704
|
+
);
|
|
2705
|
+
}
|
|
2645
2706
|
console.log();
|
|
2646
2707
|
console.log(dim(" Restart your AI tools for changes to take effect."));
|
|
2647
2708
|
console.log();
|
|
@@ -2674,7 +2735,7 @@ async function handleDisconnectTools() {
|
|
|
2674
2735
|
console.log(dim(" No tools selected."));
|
|
2675
2736
|
return;
|
|
2676
2737
|
}
|
|
2677
|
-
const proceed = await
|
|
2738
|
+
const proceed = await confirm7({
|
|
2678
2739
|
message: `Disconnect p\u0131ut from ${selected.length} tool(s)?`,
|
|
2679
2740
|
default: false
|
|
2680
2741
|
});
|
|
@@ -2692,9 +2753,62 @@ async function handleDisconnectTools() {
|
|
|
2692
2753
|
console.log(dim(" Restart your AI tools for changes to take effect."));
|
|
2693
2754
|
console.log();
|
|
2694
2755
|
}
|
|
2756
|
+
async function handleViewBrain(apiKey) {
|
|
2757
|
+
console.log(dim(" Loading brain..."));
|
|
2758
|
+
const { sections, hasUnpublishedChanges } = await getBrain(apiKey);
|
|
2759
|
+
const SECTION_LABELS = {
|
|
2760
|
+
about: "About",
|
|
2761
|
+
soul: "Soul",
|
|
2762
|
+
areas: "Areas of Responsibility",
|
|
2763
|
+
projects: "Projects",
|
|
2764
|
+
memory: "Memory"
|
|
2765
|
+
};
|
|
2766
|
+
console.log();
|
|
2767
|
+
for (const [key, label] of Object.entries(SECTION_LABELS)) {
|
|
2768
|
+
const content = sections[key] || "";
|
|
2769
|
+
if (!content.trim()) {
|
|
2770
|
+
console.log(dim(` ${label} \u2014 (empty)`));
|
|
2771
|
+
} else {
|
|
2772
|
+
console.log(success(` ${label}`));
|
|
2773
|
+
for (const line of content.split("\n")) {
|
|
2774
|
+
console.log(` ${line}`);
|
|
2775
|
+
}
|
|
2776
|
+
}
|
|
2777
|
+
console.log();
|
|
2778
|
+
}
|
|
2779
|
+
console.log(dim(` Edit at ${brand("piut.com/dashboard")}`));
|
|
2780
|
+
console.log();
|
|
2781
|
+
if (hasUnpublishedChanges) {
|
|
2782
|
+
console.log(warning(" You have unpublished changes."));
|
|
2783
|
+
console.log();
|
|
2784
|
+
const wantPublish = await confirm7({
|
|
2785
|
+
message: "Publish now?",
|
|
2786
|
+
default: true
|
|
2787
|
+
});
|
|
2788
|
+
if (wantPublish) {
|
|
2789
|
+
try {
|
|
2790
|
+
await publishServer(apiKey);
|
|
2791
|
+
console.log();
|
|
2792
|
+
console.log(success(" \u2713 Brain published."));
|
|
2793
|
+
console.log();
|
|
2794
|
+
} catch (err) {
|
|
2795
|
+
console.log();
|
|
2796
|
+
const msg = err.message;
|
|
2797
|
+
if (msg === "REQUIRES_SUBSCRIPTION") {
|
|
2798
|
+
console.log(chalk10.yellow(" Deploy requires an active subscription ($10/mo)."));
|
|
2799
|
+
console.log(` Subscribe at: ${brand("https://piut.com/dashboard/billing")}`);
|
|
2800
|
+
console.log(dim(" 14-day free trial included."));
|
|
2801
|
+
} else {
|
|
2802
|
+
console.log(chalk10.red(` \u2717 ${msg}`));
|
|
2803
|
+
}
|
|
2804
|
+
console.log();
|
|
2805
|
+
}
|
|
2806
|
+
}
|
|
2807
|
+
}
|
|
2808
|
+
}
|
|
2695
2809
|
|
|
2696
2810
|
// src/cli.ts
|
|
2697
|
-
var VERSION = "3.
|
|
2811
|
+
var VERSION = "3.5.0";
|
|
2698
2812
|
function withExit(fn) {
|
|
2699
2813
|
return async (...args2) => {
|
|
2700
2814
|
try {
|
|
@@ -2710,7 +2824,7 @@ program.name("piut").description("Build your AI brain instantly. Deploy it as an
|
|
|
2710
2824
|
if (actionCommand.name() === "update") return;
|
|
2711
2825
|
return checkForUpdate(VERSION);
|
|
2712
2826
|
}).action(interactiveMenu);
|
|
2713
|
-
program.command("build").description("Build or rebuild your brain from your files").option("-k, --key <key>", "API key").option("--folders <paths>", "Comma-separated folder paths to scan").action(withExit(buildCommand));
|
|
2827
|
+
program.command("build").description("Build or rebuild your brain from your files").option("-k, --key <key>", "API key").option("--folders <paths>", "Comma-separated folder paths to scan").option("-y, --yes", "Auto-publish after build").option("--no-publish", "Skip publish prompt after build").action(withExit(buildCommand));
|
|
2714
2828
|
program.command("deploy").description("Publish your MCP server (requires paid account)").option("-k, --key <key>", "API key").action(withExit(deployCommand));
|
|
2715
2829
|
program.command("connect").description("Add brain references to project config files").option("-k, --key <key>", "API key").option("-y, --yes", "Skip interactive prompts").option("--folders <paths>", "Comma-separated folder paths to scan").action(withExit(connectCommand));
|
|
2716
2830
|
program.command("disconnect").description("Remove brain references from project config files").option("-y, --yes", "Skip interactive prompts").option("--folders <paths>", "Comma-separated folder paths to scan").action(withExit(disconnectCommand));
|