free-pi-cli 0.6.18 → 0.6.19

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 CHANGED
@@ -27,4 +27,4 @@ if (err) {
27
27
  console.error(err);
28
28
  process.exit(1);
29
29
  }
30
- await import("./main-m86v4egg.js");
30
+ await import("./main-qn3gsj3n.js");
@@ -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.18",
518
+ version: "0.6.19",
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",
@@ -6708,6 +6708,28 @@ function loadConfig(env = process.env) {
6708
6708
 
6709
6709
  // ../pi-ads/src/api.ts
6710
6710
  import { arch } from "node:os";
6711
+
6712
+ // ../pi-ads/src/turn.ts
6713
+ var TURN_HEADER = "x-turn-id";
6714
+ var current;
6715
+ function startTurn() {
6716
+ current = crypto.randomUUID();
6717
+ return current;
6718
+ }
6719
+ var currentTurnId = () => current;
6720
+ function createTurnHeaderExtension() {
6721
+ return {
6722
+ name: "free-pi-turn-header",
6723
+ factory(pi) {
6724
+ pi.on("before_provider_headers", (event) => {
6725
+ if (current)
6726
+ event.headers[TURN_HEADER] = current;
6727
+ });
6728
+ }
6729
+ };
6730
+ }
6731
+
6732
+ // ../pi-ads/src/api.ts
6711
6733
  var REQUEST_TIMEOUT_MS = 5000;
6712
6734
  async function authedFetch(deps, path, init) {
6713
6735
  const token = await deps.getToken();
@@ -6721,7 +6743,7 @@ async function authedFetch(deps, path, init) {
6721
6743
  Authorization: `Bearer ${token}`,
6722
6744
  "Content-Type": "application/json",
6723
6745
  ...deps.sessionId && (path.startsWith("/ads/next") || path === "/ads/impression") ? { "x-session-id": deps.sessionId } : {},
6724
- ...path.startsWith("/ads/next") ? { ...deps.clientVersion ? { "x-client-version": deps.clientVersion } : {}, "x-client-os": process.platform, "x-client-arch": arch(), ...localeHeaders(), ...gravityHeader(deps) } : {}
6746
+ ...path.startsWith("/ads/next") ? { ...currentTurnId() ? { "x-turn-id": currentTurnId() } : {}, ...deps.clientVersion ? { "x-client-version": deps.clientVersion } : {}, "x-client-os": process.platform, "x-client-arch": arch(), ...localeHeaders(), ...gravityHeader(deps) } : {}
6725
6747
  }
6726
6748
  });
6727
6749
  }
@@ -6760,9 +6782,9 @@ function fireGravityImpression(deps, ad) {
6760
6782
  } catch {}
6761
6783
  return true;
6762
6784
  }
6763
- async function fetchAdNext(deps, slot) {
6785
+ async function fetchAdNext(deps, slot, trigger) {
6764
6786
  try {
6765
- const res = await authedFetch(deps, `/ads/next?slot=${slot}`);
6787
+ const res = await authedFetch(deps, `/ads/next?slot=${slot}`, trigger ? { headers: { "x-ad-trigger": trigger } } : undefined);
6766
6788
  if (res.status === 204 || !res.ok)
6767
6789
  return;
6768
6790
  return await res.json();
@@ -6862,8 +6884,8 @@ function createBannerRenderer(opts = {}) {
6862
6884
  let lastPostedToken;
6863
6885
  const screen = opts.screen ?? {};
6864
6886
  return {
6865
- async render(deps, ctx, config) {
6866
- const ad = await fetchAdNext(deps, "banner");
6887
+ async render(deps, ctx, config, trigger) {
6888
+ const ad = await fetchAdNext(deps, "banner", trigger);
6867
6889
  if (opts.isActive && !opts.isActive())
6868
6890
  return;
6869
6891
  if (!ad) {
@@ -7129,7 +7151,7 @@ async function renderMeter(deps, ctx, opts = {}) {
7129
7151
  }
7130
7152
 
7131
7153
  // ../pi-ads/src/index.ts
7132
- var BANNER_REFRESH_MS = 10 * 60 * 1000;
7154
+ var REFRESH_ON_TURN_END = false;
7133
7155
  var BANNER_MIN_REFRESH_MS = 60 * 1000;
7134
7156
  function createAdsExtension(opts) {
7135
7157
  const deps = {
@@ -7149,44 +7171,72 @@ function createAdsExtension(opts) {
7149
7171
  const screen = {};
7150
7172
  const banner = createBannerRenderer({ onBannerAd: opts.onBannerAd, isActive: () => !stopped, screen });
7151
7173
  const inline = createInlineRenderer(screen);
7152
- let bannerInterval;
7174
+ let launchTurnUnused = false;
7175
+ let launchToken;
7176
+ let launchAt = 0;
7153
7177
  let lastBannerAt = 0;
7154
7178
  let bannerInFlight = false;
7155
- const renderBanner = async (ctx, force = false) => {
7179
+ const renderBanner = async (ctx, trigger, force = false) => {
7156
7180
  if (stopped)
7157
7181
  return;
7158
7182
  if (!force && (bannerInFlight || Date.now() - lastBannerAt < BANNER_MIN_REFRESH_MS))
7159
7183
  return;
7160
7184
  bannerInFlight = true;
7161
7185
  try {
7162
- await banner.render(deps, ctx, config);
7186
+ await banner.render(deps, ctx, config, trigger);
7163
7187
  } finally {
7164
7188
  bannerInFlight = false;
7165
7189
  lastBannerAt = Date.now();
7166
7190
  }
7167
7191
  };
7192
+ pi.on("before_provider_headers", (event) => {
7193
+ const id = currentTurnId();
7194
+ if (id)
7195
+ event.headers[TURN_HEADER] = id;
7196
+ });
7168
7197
  pi.on("session_start", async (_event, ctx) => {
7169
7198
  stopped = false;
7170
7199
  inline.reset(ctx);
7200
+ startTurn();
7201
+ launchTurnUnused = true;
7202
+ launchAt = Date.now();
7203
+ launchToken = await Promise.resolve(deps.getToken()).catch(() => {
7204
+ return;
7205
+ });
7171
7206
  opts.registerMeterRefresh?.(() => renderMeter(deps, ctx));
7172
- await Promise.all([renderBanner(ctx, true), renderMeter(deps, ctx)]);
7173
- if (bannerInterval)
7174
- clearInterval(bannerInterval);
7175
- bannerInterval = setInterval(() => {
7176
- renderBanner(ctx);
7177
- }, BANNER_REFRESH_MS);
7178
- bannerInterval.unref?.();
7207
+ await Promise.all([renderBanner(ctx, "launch", true), renderMeter(deps, ctx)]);
7208
+ });
7209
+ const LAUNCH_AD_MAX_AGE_MS = 60 * 60000;
7210
+ const newMessage = async (ctx) => {
7211
+ if (launchTurnUnused) {
7212
+ launchTurnUnused = false;
7213
+ const token = await Promise.resolve(deps.getToken()).catch(() => {
7214
+ return;
7215
+ });
7216
+ if (token === launchToken && Date.now() - launchAt < LAUNCH_AD_MAX_AGE_MS)
7217
+ return;
7218
+ }
7219
+ startTurn();
7220
+ renderBanner(ctx, "user_message", true);
7221
+ };
7222
+ pi.on("before_agent_start", async (event, ctx) => {
7223
+ if (event.messageType !== "user")
7224
+ return;
7225
+ await newMessage(ctx);
7226
+ });
7227
+ pi.on("input", (event, ctx) => {
7228
+ const e = event;
7229
+ if (e.streamingBehavior && e.source !== "extension")
7230
+ return newMessage(ctx).then(() => ({ action: "continue" }));
7231
+ return { action: "continue" };
7179
7232
  });
7180
7233
  pi.on("turn_end", async (_event, ctx) => {
7181
- renderBanner(ctx);
7182
- await Promise.all([inline.onTurnEnd(deps, ctx, config), renderMeter(deps, ctx)]);
7234
+ if (REFRESH_ON_TURN_END)
7235
+ renderBanner(ctx, "turn_end");
7236
+ await renderMeter(deps, ctx);
7183
7237
  });
7184
7238
  pi.on("session_shutdown", () => {
7185
7239
  stopped = true;
7186
- if (bannerInterval) {
7187
- clearInterval(bannerInterval);
7188
- bannerInterval = undefined;
7189
- }
7190
7240
  });
7191
7241
  }
7192
7242
  };
@@ -9859,6 +9909,10 @@ function mergeAttribution(a, b) {
9859
9909
 
9860
9910
  // src/changelog.ts
9861
9911
  var CHANGELOG_HIGHLIGHTS = [
9912
+ {
9913
+ version: "0.6.19",
9914
+ highlights: ["The ad banner now refreshes when you send a message, not on a timer."]
9915
+ },
9862
9916
  {
9863
9917
  version: "0.6.18",
9864
9918
  highlights: ["Ads load correctly from your first prompt."]
@@ -14397,6 +14451,7 @@ function buildRuntimeOptions(opts, sessionId) {
14397
14451
  hasCredit: () => (getAllowanceCache()?.boughtCredits ?? 0) > 0,
14398
14452
  extensionsFor: (subSessionId) => [
14399
14453
  { name: "free-pi-subagent-provider", factory: (pi) => registerProviders(pi, subSessionId, { "x-freepi-subagent": "1" }) },
14454
+ createTurnHeaderExtension(),
14400
14455
  createToolGuardExtension({
14401
14456
  baseUrl: opts.baseUrl,
14402
14457
  getToken: () => auth.getJwt(),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "free-pi-cli",
3
- "version": "0.6.18",
3
+ "version": "0.6.19",
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",