free-pi-cli 0.6.16 → 0.6.17

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
@@ -1,3 +1,5 @@
1
+ <p align="center"><img src="https://freepi.ai/brand/free-pi-cli-lockup.png" alt="free-pi CLI" width="360"></p>
2
+
1
3
  # free-pi-cli
2
4
 
3
5
  **A free AI coding agent for your terminal.**
package/dist/index.js CHANGED
@@ -27,4 +27,4 @@ if (err) {
27
27
  console.error(err);
28
28
  process.exit(1);
29
29
  }
30
- await import("./main-gckhcg3t.js");
30
+ await import("./main-9s59pfn5.js");
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
 
3
3
  // src/main.ts
4
- import { spawn as spawn3 } from "node:child_process";
4
+ import { spawn as spawn4 } from "node:child_process";
5
5
  import { realpathSync as realpathSync8, writeFileSync as writeFileSync6 } from "node:fs";
6
6
  import { homedir as homedir10 } from "node:os";
7
7
  import { dirname as dirname14, join as join15 } from "node:path";
@@ -515,7 +515,7 @@ function folderMatches(cwd, sessionCwd) {
515
515
  // package.json
516
516
  var package_default = {
517
517
  name: "free-pi-cli",
518
- version: "0.6.16",
518
+ version: "0.6.17",
519
519
  description: "Free AI coding agent for your terminal. Ads and a daily free allowance pay for the models; sign in with GitHub and run npx free-pi-cli.",
520
520
  keywords: [
521
521
  "coding agent",
@@ -6001,6 +6001,11 @@ var AdCreativeSchema = object({
6001
6001
  cta: string2(),
6002
6002
  accent: string2()
6003
6003
  });
6004
+ var AdNextCreativeSchema = AdCreativeSchema.extend({
6005
+ icon_url: string2().optional(),
6006
+ image_url: string2().optional(),
6007
+ brand_name: string2().optional()
6008
+ });
6004
6009
  var AdNextQuerySchema = object({
6005
6010
  slot: AdSlotSchema,
6006
6011
  own_only: _enum(["1"]).optional()
@@ -6008,7 +6013,7 @@ var AdNextQuerySchema = object({
6008
6013
  var AdNextResponseSchema = object({
6009
6014
  ad_id: string2(),
6010
6015
  click_token: string2(),
6011
- creative: AdCreativeSchema,
6016
+ creative: AdNextCreativeSchema,
6012
6017
  click_url: string2(),
6013
6018
  source: _enum(["gravity", "own"]).optional(),
6014
6019
  imp_url: string2().optional()
@@ -9843,6 +9848,13 @@ function mergeAttribution(a, b) {
9843
9848
 
9844
9849
  // src/changelog.ts
9845
9850
  var CHANGELOG_HIGHLIGHTS = [
9851
+ {
9852
+ version: "0.6.17",
9853
+ highlights: [
9854
+ "free-pi now runs full screen. Click an ad to open it; selecting text still copies it, and the mouse wheel scrolls.",
9855
+ "The questions before start (terms, how you found free-pi, folder trust) now use color."
9856
+ ]
9857
+ },
9846
9858
  {
9847
9859
  version: "0.6.16",
9848
9860
  highlights: [
@@ -14035,10 +14047,83 @@ function patchResumeLine(stream) {
14035
14047
  };
14036
14048
  }
14037
14049
 
14050
+ // src/safe-url-open.ts
14051
+ import { spawn as spawn3 } from "node:child_process";
14052
+ function openLink(url) {
14053
+ if (process.platform !== "win32")
14054
+ return void openBrowser(url);
14055
+ spawn3("rundll32", ["url.dll,FileProtocolHandler", url], { stdio: "ignore", detached: true }).on("error", () => {}).unref();
14056
+ }
14057
+ function safeOpenUrl(url, open = openLink) {
14058
+ const safe = safeBrowserUrl(url);
14059
+ if (safe)
14060
+ open(safe);
14061
+ }
14062
+ function installSafeUrlOpen(mode, open = openLink) {
14063
+ const m = mode;
14064
+ const patch = (r) => {
14065
+ if (r && "openUrl" in r)
14066
+ r.openUrl = (url) => safeOpenUrl(url, open);
14067
+ };
14068
+ let current = m.renderer;
14069
+ patch(current);
14070
+ Object.defineProperty(m, "renderer", {
14071
+ configurable: true,
14072
+ enumerable: true,
14073
+ get: () => current,
14074
+ set: (next) => {
14075
+ current = next;
14076
+ patch(next);
14077
+ }
14078
+ });
14079
+ }
14080
+
14038
14081
  // src/project-trust.ts
14039
14082
  import { createInterface } from "node:readline/promises";
14040
14083
  import { resolve as resolve3 } from "node:path";
14041
14084
  import { hasTrustRequiringProjectResources, ProjectTrustStore } from "@earendil-works/pi-coding-agent";
14085
+
14086
+ // src/prelaunch-style.ts
14087
+ function colorOn() {
14088
+ return !process.env.NO_COLOR && process.stdout.isTTY === true;
14089
+ }
14090
+ var ACCENT = "96";
14091
+ var sgr2 = (code, s, on) => on ? `\x1B[${code}m${s}\x1B[0m` : s;
14092
+ function styleHeader(on = colorOn()) {
14093
+ return sgr2(`1;${ACCENT}`, "›π free-pi", on);
14094
+ }
14095
+ function styleYesNo(prompt, on = colorOn()) {
14096
+ return prompt.replace(/^(.*?)(\[y\/N\])(\s*)$/s, (_m, q, yn, sp) => `${sgr2("1", q, on)}${sgr2(ACCENT, yn, on)}${sp}`);
14097
+ }
14098
+ function styleConsent(text, on = colorOn()) {
14099
+ if (!on)
14100
+ return text;
14101
+ const body = text.split(`
14102
+ `).map((line, i) => {
14103
+ if (i === 0)
14104
+ return sgr2("1", line, on);
14105
+ if (line.startsWith("Terms:"))
14106
+ return line.replace(/https:\/\/\S+/g, (u) => sgr2(`4;${ACCENT}`, u, on));
14107
+ return sgr2("2", line, on);
14108
+ }).join(`
14109
+ `);
14110
+ return `${styleHeader(on)}
14111
+ ${body}`;
14112
+ }
14113
+ function styleSourceQuestion(q, on = colorOn()) {
14114
+ if (!on)
14115
+ return q;
14116
+ return q.replace(/How did you find free-pi\? \(optional\)/, (h) => sgr2("1", h, on)).replace(/\d\)/g, (n) => sgr2(ACCENT, n, on)).replace(/Type a number, or press Enter to skip: $/, (h) => sgr2("2", h, on));
14117
+ }
14118
+ function styleIntro(text, on = colorOn()) {
14119
+ const i = text.indexOf("npx ");
14120
+ if (i < 0)
14121
+ return text;
14122
+ return `${sgr2("2", text.slice(0, i).trimEnd(), on)}
14123
+ ${sgr2(ACCENT, text.slice(i), on)}`;
14124
+ }
14125
+
14126
+ // src/project-trust.ts
14042
14127
  var PROJECT_TRUST_PROMPT = "This folder has project settings for free-pi (.pi/ or .agents/skills), which can run code such as MCP servers and extensions. Trust this folder? [y/N] ";
14043
14128
  async function decideProjectTrust(cwd, agentDir, deps) {
14044
14129
  if (!(deps.hasTrustRequiringResources ?? hasTrustRequiringProjectResources)(cwd))
@@ -14051,7 +14136,7 @@ async function decideProjectTrust(cwd, agentDir, deps) {
14051
14136
  deps.log("This folder has project settings (.pi/ or .agents/skills); they are ignored because it is not trusted.");
14052
14137
  return false;
14053
14138
  }
14054
- const decision = /^y(es)?$/i.test((await deps.askLine(PROJECT_TRUST_PROMPT)).trim());
14139
+ const decision = /^y(es)?$/i.test((await deps.askLine(styleYesNo(PROJECT_TRUST_PROMPT))).trim());
14055
14140
  store.set(cwd, decision);
14056
14141
  return decision;
14057
14142
  }
@@ -14152,7 +14237,7 @@ function buildSettingsManager(opts, models, projectTrusted) {
14152
14237
  quietStartup: true,
14153
14238
  defaultThinkingLevel: "off",
14154
14239
  hideThinkingBlock: true,
14155
- tuiMode: "regular",
14240
+ tuiMode: "fullscreen",
14156
14241
  theme: "light/dark",
14157
14242
  enableInstallTelemetry: false,
14158
14243
  ...compactionSettingsFor(opts.costArm) ? { compaction: compactionSettingsFor(opts.costArm) } : {}
@@ -14451,6 +14536,7 @@ async function launchPi(opts) {
14451
14536
  });
14452
14537
  installLogoutHandler(mode, { credentialsPath: opts.credentialsPath, isGuest: () => auth.isGuest() });
14453
14538
  installModelAllowanceHandler(mode);
14539
+ installSafeUrlOpen(mode);
14454
14540
  installFooterRightAlign(mode, () => {
14455
14541
  const id = runtime.session?.model?.id;
14456
14542
  return freeModelBase(pickerModelName(opts, id));
@@ -14471,8 +14557,8 @@ async function promptConsent(deps, text = CONSENT_TEXT) {
14471
14557
  deps.log(NON_INTERACTIVE_CONSENT_TEXT);
14472
14558
  return false;
14473
14559
  }
14474
- deps.log(text);
14475
- const answer = await deps.askLine(CONSENT_PROMPT);
14560
+ deps.log(styleConsent(text));
14561
+ const answer = await deps.askLine(styleYesNo(CONSENT_PROMPT));
14476
14562
  return parseConsentAnswer(answer);
14477
14563
  }
14478
14564
  async function promptConsentInteractive(text) {
@@ -14664,7 +14750,7 @@ function showIntro(log, env = process.env) {
14664
14750
  if (introSkipped(env))
14665
14751
  return;
14666
14752
  log(`
14667
- ${INTRO_TEXT}
14753
+ ${styleIntro(INTRO_TEXT)}
14668
14754
  `);
14669
14755
  }
14670
14756
  var FIRST_TASK_EXPERIMENT = "retain.first_task";
@@ -14839,7 +14925,7 @@ async function promptSourceInteractive() {
14839
14925
  const rl = createInterface3({ input: process.stdin, output: process.stdout });
14840
14926
  try {
14841
14927
  return await Promise.race([
14842
- rl.question(SOURCE_QUESTION),
14928
+ rl.question(styleSourceQuestion(SOURCE_QUESTION)),
14843
14929
  new Promise((resolve) => rl.once("close", () => resolve(undefined))),
14844
14930
  new Promise((resolve) => rl.once("SIGINT", () => resolve("aborted")))
14845
14931
  ]);
@@ -15460,7 +15546,7 @@ ${HELP_TEXT}`);
15460
15546
  homedir: homedir10(),
15461
15547
  execPath: process.execPath,
15462
15548
  autoUpdateEnabled: () => readAutoUpdate(getConfigPath()),
15463
- spawn: (cmd, args, opts) => spawn3(cmd, args, opts),
15549
+ spawn: (cmd, args, opts) => spawn4(cmd, args, opts),
15464
15550
  proc: process,
15465
15551
  log: (message) => console.log(message)
15466
15552
  }),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "free-pi-cli",
3
- "version": "0.6.16",
3
+ "version": "0.6.17",
4
4
  "description": "Free AI coding agent for your terminal. Ads and a daily free allowance pay for the models; sign in with GitHub and run npx free-pi-cli.",
5
5
  "keywords": [
6
6
  "coding agent",