free-pi-cli 0.2.15 → 0.2.18

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/README.md CHANGED
@@ -5,7 +5,7 @@ for the user because ads pay for inference. All model calls route through the
5
5
  free-pi proxy — you never handle a model API key.
6
6
 
7
7
  ```
8
- npx free-pi-cli
8
+ npx --no-audit free-pi-cli
9
9
  ```
10
10
 
11
11
  First run shows a consent screen (free inference, ads pay for it, sessions
@@ -18,7 +18,7 @@ existing `~/.pi/agent` install.
18
18
  Closed the terminal? Just run the same command again — you stay signed in:
19
19
 
20
20
  ```
21
- npx free-pi-cli
21
+ npx --no-audit free-pi-cli
22
22
  ```
23
23
 
24
24
  Prefer a shorter command? Install it once, globally, then call it by name:
package/dist/index.js CHANGED
@@ -30,4 +30,4 @@ if (err) {
30
30
  console.error(err);
31
31
  process.exit(1);
32
32
  }
33
- await import("./main-d6chy61g.js");
33
+ await import("./main-9w6ygmca.js");
@@ -48,7 +48,7 @@ function openBrowser(url, platform = process.platform, spawnImpl = spawn) {
48
48
  // package.json
49
49
  var package_default = {
50
50
  name: "free-pi-cli",
51
- version: "0.2.15",
51
+ version: "0.2.18",
52
52
  description: "Free, ad-supported distribution of the pi coding agent. Inference paid for by ads.",
53
53
  license: "MIT",
54
54
  type: "module",
@@ -14774,6 +14774,7 @@ async function fetchMe(deps) {
14774
14774
  }
14775
14775
 
14776
14776
  // ../pi-ads/src/style.ts
14777
+ import { createHash } from "node:crypto";
14777
14778
  var OSC_RE = /\x1b\][\s\S]*?(?:\x07|\x1b\\)/g;
14778
14779
  var CSI_RE = /\x1b\[[0-9;?]*[ -/]*[@-~]/g;
14779
14780
  var C1_RE = /[\x80-\x9f]/g;
@@ -14793,8 +14794,9 @@ function truncate(text, maxWidth) {
14793
14794
  function pad(text, width) {
14794
14795
  return text.length >= width ? text.slice(0, width) : text + " ".repeat(width - text.length);
14795
14796
  }
14796
- function osc8(text, url2) {
14797
- return `\x1B]8;;${url2}\x07${text}\x1B]8;;\x07`;
14797
+ function osc8(text, url2, id) {
14798
+ const params = id ? `id=${id}` : "";
14799
+ return `\x1B]8;${params};${url2}\x07${text}\x1B]8;;\x07`;
14798
14800
  }
14799
14801
  function renderAdCard(creative, clickUrl, theme, columns) {
14800
14802
  const headline = sanitizeText(creative.headline);
@@ -14805,20 +14807,20 @@ function renderAdCard(creative, clickUrl, theme, columns) {
14805
14807
  const label = " AD ░▒▓ ";
14806
14808
  const top = `┌${label}${"─".repeat(Math.max(0, innerWidth + 2 - label.length))}┐`;
14807
14809
  const bottom = `└${"─".repeat(innerWidth + 2)}┘`;
14810
+ const linkId = createHash("sha256").update(url2).digest("hex").slice(0, 12);
14808
14811
  const row = (text, opts) => {
14809
14812
  const plain = pad(truncate(text, innerWidth), innerWidth);
14810
14813
  let styled = theme.fg("accent", plain);
14811
14814
  if (opts?.bold)
14812
14815
  styled = theme.bold(styled);
14813
- const content = opts?.linkUrl ? osc8(styled, opts.linkUrl) : styled;
14814
- return `│ ${content} │`;
14816
+ return `│ ${styled} │`;
14815
14817
  };
14816
14818
  return [
14817
- theme.fg("borderAccent", top),
14818
- row(headline, { bold: true }),
14819
- row(body),
14820
- row(`▸ ${cta}`, { linkUrl: url2 }),
14821
- theme.fg("borderAccent", bottom)
14819
+ theme.fg("borderAccent", osc8(top, url2, linkId)),
14820
+ osc8(row(headline, { bold: true }), url2, linkId),
14821
+ osc8(row(body), url2, linkId),
14822
+ osc8(row(`▸ ${cta}`), url2, linkId),
14823
+ theme.fg("borderAccent", osc8(bottom, url2, linkId))
14822
14824
  ];
14823
14825
  }
14824
14826
  function renderPlainAdLine(creative, clickUrl, theme, columns) {
@@ -19409,6 +19411,73 @@ function createBuyToolExtension(opts) {
19409
19411
  };
19410
19412
  }
19411
19413
 
19414
+ // src/docs.ts
19415
+ var FREE_PI_DOCS = `# free-pi
19416
+
19417
+ ## What free-pi is
19418
+ free-pi is a free, ad-supported distribution of the pi coding agent.
19419
+ You run \`npx free-pi-cli\`, sign in with GitHub, and get free inference with
19420
+ exciting models. Ads shown in the terminal pay for it. You never handle a
19421
+ model API key. Config and the sign-in token live under \`~/.free-pi/agent\`,
19422
+ separate from any \`~/.pi/agent\` install.
19423
+
19424
+ ## The promise
19425
+ Ad text never enters the model's context. Ads render only in the terminal,
19426
+ in a framed card, and the model never sees them.
19427
+ Coding sessions may be used to train models. This is on the consent screen
19428
+ at first run, before the GitHub sign-in.
19429
+
19430
+ ## The free allowance
19431
+ Each user gets a free allowance every day. The allowance can change with
19432
+ supply and demand. \`/usage\` shows how much of today's allowance is spent, as
19433
+ a percentage, with token counts.
19434
+ One session per account runs at a time. If a previous session is stuck,
19435
+ \`/close-other-session\` frees it.
19436
+
19437
+ ## Credits
19438
+ \`/buy-credits\` opens the buy page in your browser. The free allowance spends
19439
+ first. Purchased credits cover use beyond it and do not expire.
19440
+
19441
+ ## Commands
19442
+ - \`/usage\` — spend and remaining budget today
19443
+ - \`/support\` — visit today's advertiser
19444
+ - \`/tos\` — open the Terms of Service
19445
+ - \`/privacy-policy\` — open the Privacy Policy
19446
+ - \`/buy-credits\` — get more usage
19447
+ - \`/close-other-session\` — free a stuck session on another machine
19448
+ - \`/update\` — get the latest free-pi
19449
+ - \`/whats-new\` — what changed in recent releases
19450
+
19451
+ ## Support
19452
+ Today's sponsor keeps free-pi free. When the user asks how to help the
19453
+ project, or seems to like free-pi, suggest \`/support\` to visit the sponsor.
19454
+ More at https://freepi.ai
19455
+ `;
19456
+
19457
+ // src/docs-tool.ts
19458
+ var DOCS_TOOL_NAME = "free_pi_docs";
19459
+ var PARAMS3 = exports_typebox.Object({});
19460
+ function createDocsToolExtension() {
19461
+ return {
19462
+ name: "free-pi-docs-tool",
19463
+ factory(pi) {
19464
+ pi.registerTool({
19465
+ name: DOCS_TOOL_NAME,
19466
+ label: "About free-pi",
19467
+ description: "Returns the built-in free-pi guide. Read-only, takes no arguments, makes no network calls.",
19468
+ promptSnippet: "Explain free-pi itself: what it is, how the free allowance and ads work, credits, and the free-pi slash commands",
19469
+ parameters: PARAMS3,
19470
+ async execute() {
19471
+ return {
19472
+ content: [{ type: "text", text: FREE_PI_DOCS }],
19473
+ details: { ok: true }
19474
+ };
19475
+ }
19476
+ });
19477
+ }
19478
+ };
19479
+ }
19480
+
19412
19481
  // src/error-notice.ts
19413
19482
  var NOTICE_DEDUPE_MS = 15000;
19414
19483
  function parseErrorEnvelope(errorMessage) {
@@ -19480,6 +19549,26 @@ function createToolGuardExtension(opts) {
19480
19549
 
19481
19550
  // src/changelog.ts
19482
19551
  var CHANGELOG_HIGHLIGHTS = [
19552
+ {
19553
+ version: "0.2.18",
19554
+ highlights: [
19555
+ "Clearer wording in the startup consent line."
19556
+ ]
19557
+ },
19558
+ {
19559
+ version: "0.2.17",
19560
+ highlights: [
19561
+ "/tos and /privacy-policy open the Terms and Privacy Policy in your browser.",
19562
+ "The consent screen and startup header now state that usage is funded by ads and training."
19563
+ ]
19564
+ },
19565
+ {
19566
+ version: "0.2.16",
19567
+ highlights: [
19568
+ "The whole ad card is now one clickable link.",
19569
+ "Ask the agent about free-pi: it can explain the allowance, credits, and commands."
19570
+ ]
19571
+ },
19483
19572
  {
19484
19573
  version: "0.2.15",
19485
19574
  highlights: [
@@ -19644,6 +19733,16 @@ async function openAdvertiser(opts, ctx) {
19644
19733
  (opts.openBrowserImpl ?? openBrowser)(url2);
19645
19734
  ctx.ui.notify("Opening today's advertiser in your browser. Thank you for supporting free-pi.", "info");
19646
19735
  }
19736
+ var TERMS_URL = "https://freepi.ai/terms";
19737
+ var PRIVACY_URL = "https://freepi.ai/privacy";
19738
+ async function openTos(opts, ctx) {
19739
+ (opts.openBrowserImpl ?? openBrowser)(TERMS_URL);
19740
+ ctx.ui.notify(`Opening the Terms of Service in your browser: ${TERMS_URL}`, "info");
19741
+ }
19742
+ async function openPrivacyPolicy(opts, ctx) {
19743
+ (opts.openBrowserImpl ?? openBrowser)(PRIVACY_URL);
19744
+ ctx.ui.notify(`Opening the Privacy Policy in your browser: ${PRIVACY_URL}`, "info");
19745
+ }
19647
19746
  async function showUsage(opts, ctx) {
19648
19747
  const r = await fetchUsageText(opts);
19649
19748
  ctx.ui.notify(r.text, r.ok ? "info" : "error");
@@ -19676,6 +19775,14 @@ function createFreePiCommandsExtension(opts) {
19676
19775
  description: "Open today's advertiser in your browser to support free-pi.",
19677
19776
  handler: (_args, ctx) => openAdvertiser(opts, ctx)
19678
19777
  });
19778
+ pi.registerCommand("tos", {
19779
+ description: "Open the free-pi Terms of Service in your browser.",
19780
+ handler: (_args, ctx) => openTos(opts, ctx)
19781
+ });
19782
+ pi.registerCommand("privacy-policy", {
19783
+ description: "Open the free-pi Privacy Policy in your browser.",
19784
+ handler: (_args, ctx) => openPrivacyPolicy(opts, ctx)
19785
+ });
19679
19786
  }
19680
19787
  };
19681
19788
  }
@@ -19684,12 +19791,16 @@ function createFreePiCommandsExtension(opts) {
19684
19791
  var COMMANDS = [
19685
19792
  { name: "/usage", description: "spend and remaining budget today" },
19686
19793
  { name: "/support", description: "visit today's advertiser" },
19794
+ { name: "/tos", description: "terms of service" },
19795
+ { name: "/privacy-policy", description: "privacy policy" },
19687
19796
  { name: "/buy-credits", description: "get more usage" },
19688
19797
  { name: "/close-other-session", description: "free a stuck session on another machine" },
19689
19798
  { name: "/update", description: "get the latest free-pi" }
19690
19799
  ];
19691
19800
  var NAME_COLUMN = 24;
19692
19801
  var WELCOME_LINE = "Welcome to Free Pi, ad-supported inference. Please visit our advertisers to support us.";
19802
+ var CONSENT_LINE_1 = "Usage is funded by ads and training. By using free-pi you consent.";
19803
+ var CONSENT_LINE_2 = "See /tos and /privacy-policy.";
19693
19804
  var EXPANDED_HINT_LINE = "esc interrupt · ctrl+c clear / exit · / commands · ! bash";
19694
19805
  function truncate2(text, maxWidth) {
19695
19806
  if (maxWidth <= 0)
@@ -19710,7 +19821,18 @@ function headerLines(theme, modelName, expanded, width = Number.POSITIVE_INFINIT
19710
19821
  return fit(`${padded}${description}`, () => `${padded}${theme.fg("dim", description)}`);
19711
19822
  });
19712
19823
  const dim = (plain) => fit(plain, () => theme.fg("dim", plain));
19713
- const lines = ["", title, "", dim(WELCOME_LINE), "", ...commandLines, ""];
19824
+ const lines = [
19825
+ "",
19826
+ title,
19827
+ "",
19828
+ dim(WELCOME_LINE),
19829
+ "",
19830
+ dim(CONSENT_LINE_1),
19831
+ dim(CONSENT_LINE_2),
19832
+ "",
19833
+ ...commandLines,
19834
+ ""
19835
+ ];
19714
19836
  if (expanded)
19715
19837
  lines.push(dim(EXPANDED_HINT_LINE));
19716
19838
  return lines.map((line) => line === "" ? line : ` ${line}`);
@@ -19758,7 +19880,7 @@ function catalogModelsFor(opts) {
19758
19880
  const id = opts.model || MODEL_ID;
19759
19881
  return [{ id, name: id }];
19760
19882
  }
19761
- var ALLOWED_TOOL_NAMES = [...SAFE_TOOLS, USAGE_TOOL_NAME, BUY_TOOL_NAME];
19883
+ var ALLOWED_TOOL_NAMES = [...SAFE_TOOLS, USAGE_TOOL_NAME, BUY_TOOL_NAME, DOCS_TOOL_NAME];
19762
19884
  function resolveModelName(opts) {
19763
19885
  return opts.models?.[0]?.name || opts.model || MODEL_ID;
19764
19886
  }
@@ -19787,6 +19909,7 @@ function buildRuntimeOptions(opts, sessionId) {
19787
19909
  baseUrl: opts.baseUrl,
19788
19910
  getToken: () => opts.jwt
19789
19911
  });
19912
+ const docsToolExtension = createDocsToolExtension();
19790
19913
  const errorNoticeExtension = createErrorNoticeExtension();
19791
19914
  const toolGuardExtension = createToolGuardExtension({
19792
19915
  baseUrl: opts.baseUrl,
@@ -19806,6 +19929,7 @@ function buildRuntimeOptions(opts, sessionId) {
19806
19929
  adsExtension,
19807
19930
  usageToolExtension,
19808
19931
  buyToolExtension,
19932
+ docsToolExtension,
19809
19933
  errorNoticeExtension,
19810
19934
  toolGuardExtension,
19811
19935
  commandsExtension,
@@ -19892,18 +20016,28 @@ import { createInterface } from "node:readline/promises";
19892
20016
  var CONSENT_TEXT = `
19893
20017
  free-pi — before you start
19894
20018
 
19895
- * Inference is free. Ads pay for it.
19896
- * A persistent ad banner and occasional inline ad cards render in the
19897
- terminal UI. Ad content never enters the model's context.
19898
- * Your coding sessions may be used to train models.
20019
+ * Inference is free. Ads pay for it, and so does training.
20020
+ * Ad cards render in the terminal UI. Ad content never enters the model's
20021
+ context.
20022
+ * Your coding sessions (prompts, code, files, and model responses) are saved
20023
+ as traces and used to train models. We may share or sell that data to
20024
+ third parties. Once you accept, there is no opt-out, except where the law
20025
+ gives you one.
20026
+ * We do our best to remove personal information from traces before we store
20027
+ them. We cannot promise it is perfectly clean.
20028
+ * free-pi is in alpha and testing. There are no warranties or guarantees,
20029
+ expressed or implied, and no guarantee of uptime.
19899
20030
  * If GitHub email capture is enabled, we collect your GitHub email and may
19900
20031
  use it to contact you about the service or product.
19901
20032
  * free-pi-cli auto-updates itself when a new version is available. Disable
19902
20033
  with FREEPI_NO_AUTO_UPDATE or {"autoUpdate":false} in ~/.free-pi/config.json.
19903
20034
 
20035
+ By accepting you agree to the Terms of Service (https://freepi.ai/terms)
20036
+ and the Privacy Policy (https://freepi.ai/privacy).
20037
+
19904
20038
  Decline and nothing is sent to the free-pi server.
19905
20039
  `.trim();
19906
- var CONSENT_VERSION = "1";
20040
+ var CONSENT_VERSION = "2";
19907
20041
  var NON_INTERACTIVE_CONSENT_TEXT = "free-pi first-run consent needs an interactive terminal (stdin is not a TTY). " + "Run `npx free-pi-cli` in a terminal once to review and accept; " + "after that, non-interactive runs work.";
19908
20042
  var CONSENT_PROMPT = "Accept? [y/N] ";
19909
20043
  function parseConsentAnswer(answer) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "free-pi-cli",
3
- "version": "0.2.15",
3
+ "version": "0.2.18",
4
4
  "description": "Free, ad-supported distribution of the pi coding agent. Inference paid for by ads.",
5
5
  "license": "MIT",
6
6
  "type": "module",