free-pi-cli 0.2.19 → 0.3.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 +1 -1
- package/dist/{main-tc7xq892.js → main-376chsck.js} +114 -14
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -44,7 +44,7 @@ function openBrowser(url, platform = process.platform, spawnImpl = spawn) {
|
|
|
44
44
|
// package.json
|
|
45
45
|
var package_default = {
|
|
46
46
|
name: "free-pi-cli",
|
|
47
|
-
version: "0.
|
|
47
|
+
version: "0.3.0",
|
|
48
48
|
description: "Free, ad-supported distribution of the pi coding agent. Inference paid for by ads.",
|
|
49
49
|
license: "MIT",
|
|
50
50
|
type: "module",
|
|
@@ -63,7 +63,7 @@ var package_default = {
|
|
|
63
63
|
prepublishOnly: "bun run build"
|
|
64
64
|
},
|
|
65
65
|
dependencies: {
|
|
66
|
-
"@earendil-works/pi-coding-agent": "
|
|
66
|
+
"@earendil-works/pi-coding-agent": "1.2.0"
|
|
67
67
|
},
|
|
68
68
|
devDependencies: {
|
|
69
69
|
"@freepi/pi-ads": "workspace:*",
|
|
@@ -80,10 +80,11 @@ var HELP_TEXT = `
|
|
|
80
80
|
free-pi — free AI coding in your terminal; ads pay for the inference.
|
|
81
81
|
|
|
82
82
|
Usage:
|
|
83
|
-
free-pi-cli
|
|
84
|
-
free-pi-cli
|
|
85
|
-
free-pi-cli
|
|
86
|
-
free-pi-cli --
|
|
83
|
+
free-pi-cli start the coding agent (first run: consent + GitHub sign-in)
|
|
84
|
+
free-pi-cli --session <id> resume a previous session
|
|
85
|
+
free-pi-cli logout remove the stored sign-in token; the next run signs in again
|
|
86
|
+
free-pi-cli --version print the CLI version
|
|
87
|
+
free-pi-cli --help show this help
|
|
87
88
|
|
|
88
89
|
Environment:
|
|
89
90
|
FREEPI_BASE_URL override the backend base URL (default https://api.freepi.ai)
|
|
@@ -96,6 +97,9 @@ function parseCliArgs(argv) {
|
|
|
96
97
|
const [first, ...rest] = argv;
|
|
97
98
|
if (first === undefined)
|
|
98
99
|
return { kind: "run" };
|
|
100
|
+
if (first === "--session") {
|
|
101
|
+
return rest.length > 1 ? { kind: "unknown", arg: rest[1] } : { kind: "run" };
|
|
102
|
+
}
|
|
99
103
|
let kind;
|
|
100
104
|
if (first === "--help" || first === "-h" || first === "help")
|
|
101
105
|
kind = "help";
|
|
@@ -4851,6 +4855,13 @@ var ClientVersionResponseSchema = object({
|
|
|
4851
4855
|
var SessionResetResponseSchema = object({
|
|
4852
4856
|
released: boolean2()
|
|
4853
4857
|
});
|
|
4858
|
+
var BugReportRequestSchema = object({
|
|
4859
|
+
description: string2().trim().min(1).max(4000),
|
|
4860
|
+
session_id: string2().max(128).optional(),
|
|
4861
|
+
cli_version: string2().max(32).optional(),
|
|
4862
|
+
model: string2().max(128).optional()
|
|
4863
|
+
});
|
|
4864
|
+
var BugReportResponseSchema = object({ id: string2() });
|
|
4854
4865
|
// ../shared/src/errors.ts
|
|
4855
4866
|
function assertExhaustiveErrorCode(code) {
|
|
4856
4867
|
throw new Error(`unhandled error code: ${String(code)}`);
|
|
@@ -4865,6 +4876,8 @@ var ConfigSchema = object({
|
|
|
4865
4876
|
accountsPerDayCeiling: number2().int().default(500),
|
|
4866
4877
|
authRatePerIpPerHour: number2().int().default(30),
|
|
4867
4878
|
webBuyUrlRatePerProviderPerHour: number2().int().default(20),
|
|
4879
|
+
handoffTokenRatePerProviderPerHour: number2().int().default(60),
|
|
4880
|
+
handoffHourlyCompletionCap: number2().int().default(120),
|
|
4868
4881
|
tokenRatePerIpPerHour: number2().int().default(3600),
|
|
4869
4882
|
consentRatePerIpPerHour: number2().int().default(60),
|
|
4870
4883
|
adInlineTurnFrequency: number2().int().default(5),
|
|
@@ -4931,6 +4944,8 @@ function loadConfig(env = process.env) {
|
|
|
4931
4944
|
accountsPerDayCeiling: envNumber(env.ACCOUNTS_PER_DAY_CEILING),
|
|
4932
4945
|
authRatePerIpPerHour: envNumber(env.AUTH_RATE_PER_IP_PER_HOUR),
|
|
4933
4946
|
webBuyUrlRatePerProviderPerHour: envNumber(env.WEB_BUY_URL_RATE_PER_PROVIDER_PER_HOUR),
|
|
4947
|
+
handoffTokenRatePerProviderPerHour: envNumber(env.HANDOFF_TOKEN_RATE_PER_PROVIDER_PER_HOUR),
|
|
4948
|
+
handoffHourlyCompletionCap: envNumber(env.HANDOFF_HOURLY_COMPLETION_CAP),
|
|
4934
4949
|
tokenRatePerIpPerHour: envNumber(env.TOKEN_RATE_PER_IP_PER_HOUR),
|
|
4935
4950
|
consentRatePerIpPerHour: envNumber(env.CONSENT_RATE_PER_IP_PER_HOUR),
|
|
4936
4951
|
adInlineTurnFrequency: envNumber(env.AD_INLINE_TURN_FREQUENCY),
|
|
@@ -5186,6 +5201,8 @@ function mapErrorCode(code) {
|
|
|
5186
5201
|
return "too many requests this hour on the free tier — wait for the Retry-After window";
|
|
5187
5202
|
case "account_review":
|
|
5188
5203
|
return "this account is under review — contact support";
|
|
5204
|
+
case "ads_required":
|
|
5205
|
+
return "ads aren't displaying for this account, so free completions are paused — run free-pi through `npx free-pi-cli`, then retry";
|
|
5189
5206
|
default:
|
|
5190
5207
|
return assertExhaustiveErrorCode(code);
|
|
5191
5208
|
}
|
|
@@ -5573,9 +5590,10 @@ exciting models. Ads shown in the terminal pay for it. You never handle a
|
|
|
5573
5590
|
model API key. Config and the sign-in token live under \`~/.free-pi/agent\`,
|
|
5574
5591
|
separate from any \`~/.pi/agent\` install.
|
|
5575
5592
|
|
|
5576
|
-
##
|
|
5577
|
-
|
|
5578
|
-
|
|
5593
|
+
## Ads and your data
|
|
5594
|
+
Ads render in the terminal, in a framed card. Some ads come from Gravity, a
|
|
5595
|
+
third-party ad provider that receives excerpts of your recent conversation
|
|
5596
|
+
to pick a relevant ad.
|
|
5579
5597
|
Coding sessions may be used to train models. This is on the consent screen
|
|
5580
5598
|
at first run, before the GitHub sign-in.
|
|
5581
5599
|
|
|
@@ -5699,8 +5717,83 @@ function createToolGuardExtension(opts) {
|
|
|
5699
5717
|
};
|
|
5700
5718
|
}
|
|
5701
5719
|
|
|
5720
|
+
// src/bug-report.ts
|
|
5721
|
+
var BUG_USAGE = "Usage: /bug <what went wrong>";
|
|
5722
|
+
var BUG_DESCRIPTION = "Report a bug to free-pi";
|
|
5723
|
+
function buildBugRequest(description, ctx) {
|
|
5724
|
+
return { description, session_id: ctx.sessionId, cli_version: CLI_VERSION, model: ctx.model };
|
|
5725
|
+
}
|
|
5726
|
+
function mapBugFailure(status) {
|
|
5727
|
+
if (status === 401)
|
|
5728
|
+
return "Couldn't send the bug report: you're signed out. Restart free-pi-cli to sign in again.";
|
|
5729
|
+
if (status === 429)
|
|
5730
|
+
return "Couldn't send the bug report: you've reached today's limit of 20 reports. Try again tomorrow.";
|
|
5731
|
+
if (status === 413)
|
|
5732
|
+
return "Couldn't send the bug report: it is too large.";
|
|
5733
|
+
if (status === 400)
|
|
5734
|
+
return "Couldn't send the bug report: the description is too long (4000 characters max).";
|
|
5735
|
+
return `Couldn't send the bug report (the server returned ${status}). Try again in a moment.`;
|
|
5736
|
+
}
|
|
5737
|
+
async function sendBugReport(opts, body) {
|
|
5738
|
+
try {
|
|
5739
|
+
const res = await (opts.fetchImpl ?? fetch)(`${opts.baseUrl}/bug-reports`, {
|
|
5740
|
+
method: "POST",
|
|
5741
|
+
headers: { Authorization: `Bearer ${await opts.getToken()}`, "Content-Type": "application/json" },
|
|
5742
|
+
body: JSON.stringify(body),
|
|
5743
|
+
signal: AbortSignal.timeout(1e4)
|
|
5744
|
+
});
|
|
5745
|
+
if (!res.ok)
|
|
5746
|
+
return { ok: false, message: mapBugFailure(res.status) };
|
|
5747
|
+
const parsed = BugReportResponseSchema.safeParse(await res.json());
|
|
5748
|
+
if (!parsed.success)
|
|
5749
|
+
return { ok: false, message: mapBugFailure(res.status) };
|
|
5750
|
+
return { ok: true, id: parsed.data.id };
|
|
5751
|
+
} catch {
|
|
5752
|
+
return { ok: false, message: "Couldn't reach free-pi to send the bug report — check your connection." };
|
|
5753
|
+
}
|
|
5754
|
+
}
|
|
5755
|
+
function makeBugHandler(mode, opts) {
|
|
5756
|
+
return async (hint) => {
|
|
5757
|
+
if (!hint)
|
|
5758
|
+
return mode.showStatus(BUG_USAGE);
|
|
5759
|
+
const r = await sendBugReport(opts, buildBugRequest(hint, { sessionId: mode.session.sessionId, model: mode.session.model?.id }));
|
|
5760
|
+
if (r.ok)
|
|
5761
|
+
return mode.showStatus(`Thanks — bug report received (#${r.id}).`);
|
|
5762
|
+
if (!mode.editor.getText())
|
|
5763
|
+
mode.editor.setText(`/bug ${hint}`);
|
|
5764
|
+
mode.showError(r.message);
|
|
5765
|
+
};
|
|
5766
|
+
}
|
|
5767
|
+
function installBugHandler(mode, opts) {
|
|
5768
|
+
mode.handleBugCommand = makeBugHandler(mode, opts);
|
|
5769
|
+
}
|
|
5770
|
+
function registerBugAutocomplete(pi) {
|
|
5771
|
+
pi.on("session_start", (_event, ctx) => {
|
|
5772
|
+
ctx.ui.addAutocompleteProvider((cur) => ({
|
|
5773
|
+
triggerCharacters: cur.triggerCharacters,
|
|
5774
|
+
applyCompletion: (...a) => cur.applyCompletion(...a),
|
|
5775
|
+
shouldTriggerFileCompletion: cur.shouldTriggerFileCompletion?.bind(cur),
|
|
5776
|
+
getSuggestions: async (...a) => {
|
|
5777
|
+
const r = await cur.getSuggestions(...a);
|
|
5778
|
+
return r && {
|
|
5779
|
+
...r,
|
|
5780
|
+
items: r.items.map((i) => i.value === "bug" && i.label === "bug" ? { ...i, description: BUG_DESCRIPTION } : i)
|
|
5781
|
+
};
|
|
5782
|
+
}
|
|
5783
|
+
}));
|
|
5784
|
+
});
|
|
5785
|
+
}
|
|
5786
|
+
|
|
5702
5787
|
// src/changelog.ts
|
|
5703
5788
|
var CHANGELOG_HIGHLIGHTS = [
|
|
5789
|
+
{
|
|
5790
|
+
version: "0.3.0",
|
|
5791
|
+
highlights: [
|
|
5792
|
+
"Upgraded the underlying pi agent engine to 1.2.0.",
|
|
5793
|
+
"/bug now sends reports to the free-pi team.",
|
|
5794
|
+
"`npx free-pi-cli --session <id>` resumes a session again."
|
|
5795
|
+
]
|
|
5796
|
+
},
|
|
5704
5797
|
{
|
|
5705
5798
|
version: "0.2.19",
|
|
5706
5799
|
highlights: [
|
|
@@ -5911,6 +6004,7 @@ function createFreePiCommandsExtension(opts) {
|
|
|
5911
6004
|
return {
|
|
5912
6005
|
name: "free-pi-commands",
|
|
5913
6006
|
factory(pi) {
|
|
6007
|
+
registerBugAutocomplete(pi);
|
|
5914
6008
|
pi.registerCommand("close-other-session", {
|
|
5915
6009
|
description: "Clear your other running free-pi session (use if a previous one is stuck).",
|
|
5916
6010
|
handler: (_args, ctx) => closeOtherSession(opts, ctx)
|
|
@@ -6054,7 +6148,7 @@ function resolveFreePiScope(modelRuntime, providerName, modelIds, env = process.
|
|
|
6054
6148
|
|
|
6055
6149
|
// src/resume-line.ts
|
|
6056
6150
|
var RESUME_LABEL = "To resume this session:";
|
|
6057
|
-
var RESUME_COMMAND_RE = /(To resume this session:(?:\u001b\[[0-9;]*m|\s)*)pi(?=\s)
|
|
6151
|
+
var RESUME_COMMAND_RE = /(To resume this session:(?:\u001b\[[0-9;]*m|\s)*)pi(?=\s)( --session-dir (?:'(?:[^']|'\\'')*'|\S+))?/g;
|
|
6058
6152
|
function rewriteResumeLine(chunk) {
|
|
6059
6153
|
if (!chunk.includes(RESUME_LABEL))
|
|
6060
6154
|
return chunk;
|
|
@@ -6140,7 +6234,10 @@ function buildRuntimeOptions(opts, sessionId) {
|
|
|
6140
6234
|
defaultModel: models[0].id,
|
|
6141
6235
|
defaultTools: [...SAFE_TOOLS],
|
|
6142
6236
|
packages: [],
|
|
6143
|
-
quietStartup: true
|
|
6237
|
+
quietStartup: true,
|
|
6238
|
+
tuiMode: "regular",
|
|
6239
|
+
theme: "light/dark",
|
|
6240
|
+
enableInstallTelemetry: false
|
|
6144
6241
|
});
|
|
6145
6242
|
return {
|
|
6146
6243
|
settingsManager,
|
|
@@ -6166,6 +6263,7 @@ async function createSessionManager(cwd, sessionDir, sessionId, api = SessionMan
|
|
|
6166
6263
|
return api.create(cwd, sessionDir);
|
|
6167
6264
|
}
|
|
6168
6265
|
process.env.PI_SKIP_VERSION_CHECK = "1";
|
|
6266
|
+
process.env.PI_TELEMETRY = "0";
|
|
6169
6267
|
patchResumeLine(process.stdout);
|
|
6170
6268
|
async function launchPi(opts) {
|
|
6171
6269
|
const cwd = process.cwd();
|
|
@@ -6207,6 +6305,7 @@ async function launchPi(opts) {
|
|
|
6207
6305
|
initialImages: [],
|
|
6208
6306
|
initialMessages: []
|
|
6209
6307
|
});
|
|
6308
|
+
installBugHandler(mode, { baseUrl: opts.baseUrl, getToken: () => opts.jwt });
|
|
6210
6309
|
await mode.run();
|
|
6211
6310
|
return sm.getSessionId();
|
|
6212
6311
|
}
|
|
@@ -6219,8 +6318,9 @@ var CONSENT_TEXT = `
|
|
|
6219
6318
|
free-pi — before you start
|
|
6220
6319
|
|
|
6221
6320
|
* Inference is free. Ads pay for it, and so does training.
|
|
6222
|
-
* Ad cards render in the terminal UI.
|
|
6223
|
-
|
|
6321
|
+
* Ad cards render in the terminal UI. Some ads come from a third-party ad
|
|
6322
|
+
provider (Gravity), which receives excerpts of your recent conversation
|
|
6323
|
+
to pick a relevant ad.
|
|
6224
6324
|
* Your coding sessions (prompts, code, files, and model responses) are saved
|
|
6225
6325
|
as traces and used to train models. We may share or sell that data to
|
|
6226
6326
|
third parties. Once you accept, there is no opt-out, except where the law
|
|
@@ -6239,7 +6339,7 @@ and the Privacy Policy (https://freepi.ai/privacy).
|
|
|
6239
6339
|
|
|
6240
6340
|
Decline and nothing is sent to the free-pi server.
|
|
6241
6341
|
`.trim();
|
|
6242
|
-
var CONSENT_VERSION = "
|
|
6342
|
+
var CONSENT_VERSION = "3";
|
|
6243
6343
|
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.";
|
|
6244
6344
|
var CONSENT_PROMPT = "Accept? [y/N] ";
|
|
6245
6345
|
function parseConsentAnswer(answer) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "free-pi-cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
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",
|
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
"prepublishOnly": "bun run build"
|
|
20
20
|
},
|
|
21
21
|
"dependencies": {
|
|
22
|
-
"@earendil-works/pi-coding-agent": "
|
|
22
|
+
"@earendil-works/pi-coding-agent": "1.2.0"
|
|
23
23
|
},
|
|
24
24
|
"devDependencies": {
|
|
25
25
|
"@freepi/pi-ads": "workspace:*",
|