free-pi-cli 0.6.15 → 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 +2 -0
- package/dist/index.js +1 -1
- package/dist/{main-jmyqcr54.js → main-9s59pfn5.js} +153 -21
- package/package.json +1 -1
package/README.md
CHANGED
package/dist/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
3
|
// src/main.ts
|
|
4
|
-
import { spawn as
|
|
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.
|
|
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:
|
|
6016
|
+
creative: AdNextCreativeSchema,
|
|
6012
6017
|
click_url: string2(),
|
|
6013
6018
|
source: _enum(["gravity", "own"]).optional(),
|
|
6014
6019
|
imp_url: string2().optional()
|
|
@@ -7030,11 +7035,14 @@ function formatRewardStatus(r, now, columns) {
|
|
|
7030
7035
|
}
|
|
7031
7036
|
async function renderMeter(deps, ctx, opts = {}) {
|
|
7032
7037
|
const me = await fetchMe(deps);
|
|
7033
|
-
ctx.ui.setStatus(METER_STATUS_KEY, undefined);
|
|
7034
7038
|
if (!me) {
|
|
7035
|
-
|
|
7039
|
+
if (await deps.getToken() !== lastToken) {
|
|
7040
|
+
ctx.ui.setStatus(METER_STATUS_KEY, undefined);
|
|
7041
|
+
ctx.ui.setWidget(METER_WIDGET_ID, undefined);
|
|
7042
|
+
}
|
|
7036
7043
|
return;
|
|
7037
7044
|
}
|
|
7045
|
+
ctx.ui.setStatus(METER_STATUS_KEY, undefined);
|
|
7038
7046
|
const theme = ctx.ui.theme;
|
|
7039
7047
|
const reward = formatRewardStatus(me.earn_reward, opts.now ?? Date.now(), opts.columns ?? (process.stdout.columns || 80));
|
|
7040
7048
|
if (reward)
|
|
@@ -8915,10 +8923,10 @@ function createToolAliasesExtension(opts = {}) {
|
|
|
8915
8923
|
var FUSION_ID = "fusion";
|
|
8916
8924
|
var FUSION_PICKER_ID = "\uD83E\uDDE8 fusion";
|
|
8917
8925
|
var FUSION_NAME = "\uD83E\uDDE8 Fusion · DeepSeek Pro plans, Flash builds";
|
|
8918
|
-
var FUSION_FALLBACK_NAME = "\uD83E\uDDE8 Fusion ·
|
|
8926
|
+
var FUSION_FALLBACK_NAME = "\uD83E\uDDE8 Fusion · DeepSeek Flash plans and builds";
|
|
8919
8927
|
var FUSION_PLANNER_ID = "deepseek-v4-pro";
|
|
8920
8928
|
var FUSION_EXECUTOR_ID = "deepseek-v4-flash";
|
|
8921
|
-
var FUSION_FALLBACK_PLANNER_ID = "
|
|
8929
|
+
var FUSION_FALLBACK_PLANNER_ID = "deepseek-v4-flash";
|
|
8922
8930
|
function resolveFusionIds(catalogIds, server) {
|
|
8923
8931
|
const has = (id) => catalogIds.includes(id);
|
|
8924
8932
|
if (server && has(server.planner) && has(server.executor))
|
|
@@ -9200,7 +9208,7 @@ var LIMIT_CODES = new Set([
|
|
|
9200
9208
|
"context_too_long",
|
|
9201
9209
|
"reward_required"
|
|
9202
9210
|
]);
|
|
9203
|
-
var SERVER_MESSAGE_CODES = new Set(["reward_required", "premium_allowance", "model_at_capacity", "context_too_long_for_fallback", "context_too_long"]);
|
|
9211
|
+
var SERVER_MESSAGE_CODES = new Set(["concurrent", "reward_required", "premium_allowance", "model_at_capacity", "context_too_long_for_fallback", "context_too_long"]);
|
|
9204
9212
|
var FREE_OFFER_CODES = new Set(["daily_cap", "queue_wait", "rolling_cap", "premium_allowance", "model_at_capacity", "model_requires_credits"]);
|
|
9205
9213
|
var isFusion = (model) => model?.provider === PROVIDER_NAME && (model.id === FUSION_ID || model.id === FUSION_PICKER_ID);
|
|
9206
9214
|
function lastUserEntryId(ctx) {
|
|
@@ -9840,6 +9848,21 @@ function mergeAttribution(a, b) {
|
|
|
9840
9848
|
|
|
9841
9849
|
// src/changelog.ts
|
|
9842
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
|
+
},
|
|
9858
|
+
{
|
|
9859
|
+
version: "0.6.16",
|
|
9860
|
+
highlights: [
|
|
9861
|
+
"New premium model: DeepSeek V4.1 Flash Ultrafast. Find it in /model as \uD83D\uDD25\uD83D\uDD25\uD83D\uDD25 ultrafast. It uses premium credits only.",
|
|
9862
|
+
"Subagents now need credits: they use premium credit, and up to 4 run at once.",
|
|
9863
|
+
"Fusion plans with DeepSeek Flash, since the Claude models are retired."
|
|
9864
|
+
]
|
|
9865
|
+
},
|
|
9843
9866
|
{
|
|
9844
9867
|
version: "0.6.15",
|
|
9845
9868
|
highlights: [
|
|
@@ -11995,12 +12018,40 @@ function createHeaderExtension(opts) {
|
|
|
11995
12018
|
};
|
|
11996
12019
|
}
|
|
11997
12020
|
|
|
12021
|
+
// src/ultrafast.ts
|
|
12022
|
+
var ULTRAFAST_THINKING_LEVELS = ["off", "minimal", "low", "medium", "high"];
|
|
12023
|
+
var ULTRAFAST_CATALOG_ID = "deepseek-v4.1-flash-1017-ultrafast";
|
|
12024
|
+
var ULTRAFAST_PICKER_ID = "\uD83D\uDD25\uD83D\uDD25\uD83D\uDD25 ultrafast";
|
|
12025
|
+
function createUltrafastExtension(model) {
|
|
12026
|
+
return {
|
|
12027
|
+
name: "free-pi-ultrafast",
|
|
12028
|
+
factory(pi) {
|
|
12029
|
+
if (!model || model.id !== ULTRAFAST_CATALOG_ID)
|
|
12030
|
+
return;
|
|
12031
|
+
pi.registerVirtualModel({
|
|
12032
|
+
provider: PROVIDER_NAME,
|
|
12033
|
+
id: ULTRAFAST_PICKER_ID,
|
|
12034
|
+
name: model.name,
|
|
12035
|
+
input: ["text"],
|
|
12036
|
+
thinkingLevels: ULTRAFAST_THINKING_LEVELS,
|
|
12037
|
+
contextWindow: CONTEXT_WINDOW,
|
|
12038
|
+
maxTokens: MAX_OUTPUT_TOKENS,
|
|
12039
|
+
route: (_request, ctx) => ({
|
|
12040
|
+
model: ctx.modelRegistry.find(PROVIDER_NAME, ULTRAFAST_CATALOG_ID),
|
|
12041
|
+
thinkingLevel: _request.thinkingLevel
|
|
12042
|
+
})
|
|
12043
|
+
});
|
|
12044
|
+
}
|
|
12045
|
+
};
|
|
12046
|
+
}
|
|
12047
|
+
|
|
11998
12048
|
// src/provider-lock.ts
|
|
11999
12049
|
function resolveFreePiScope(modelRuntime, providerName, modelIds, env = process.env) {
|
|
12000
12050
|
if (env.FREEPI_KEEP_ENV_PROVIDERS)
|
|
12001
12051
|
return [];
|
|
12002
12052
|
const scoped = [];
|
|
12003
|
-
|
|
12053
|
+
const pickerModelIds = modelIds.map((id) => id === ULTRAFAST_CATALOG_ID ? ULTRAFAST_PICKER_ID : id);
|
|
12054
|
+
for (const id of new Set([FUSION_PICKER_ID, ...pickerModelIds])) {
|
|
12004
12055
|
const model = modelRuntime.getModel(providerName, id);
|
|
12005
12056
|
if (model)
|
|
12006
12057
|
scoped.push({ model });
|
|
@@ -12032,19 +12083,22 @@ var SEND_MESSAGE_TOOL = "send_message";
|
|
|
12032
12083
|
var SUBMIT_PLAN_TOOL = "submit_plan";
|
|
12033
12084
|
var MAX_PARALLEL = 8;
|
|
12034
12085
|
var PARTICLE_ID = "particle";
|
|
12035
|
-
var REFUSAL_FALLBACK = "Subagents
|
|
12086
|
+
var REFUSAL_FALLBACK = "Subagents need credits. Run /buy-credits.";
|
|
12036
12087
|
function subagentModelId(agent, parentModelId, ids) {
|
|
12037
12088
|
if (parentModelId === PARTICLE_ID)
|
|
12038
12089
|
return PARTICLE_ID;
|
|
12039
12090
|
if (agent === "planner")
|
|
12040
12091
|
return ids.planner;
|
|
12092
|
+
if (parentModelId === ULTRAFAST_PICKER_ID)
|
|
12093
|
+
return ULTRAFAST_CATALOG_ID;
|
|
12041
12094
|
return parentModelId === FUSION_ID || parentModelId === FUSION_PICKER_ID ? ids.executor : parentModelId;
|
|
12042
12095
|
}
|
|
12043
|
-
function subagentsAvailable(
|
|
12044
|
-
return
|
|
12096
|
+
function subagentsAvailable(_modelId, hasCredit) {
|
|
12097
|
+
return hasCredit;
|
|
12045
12098
|
}
|
|
12046
|
-
|
|
12047
|
-
|
|
12099
|
+
var SUBAGENT_CONCURRENCY = 4;
|
|
12100
|
+
function subagentConcurrency(_modelId) {
|
|
12101
|
+
return SUBAGENT_CONCURRENCY;
|
|
12048
12102
|
}
|
|
12049
12103
|
function substitutePrevious(task, previous) {
|
|
12050
12104
|
return task.split("{previous}").join(previous);
|
|
@@ -13993,10 +14047,83 @@ function patchResumeLine(stream) {
|
|
|
13993
14047
|
};
|
|
13994
14048
|
}
|
|
13995
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
|
+
|
|
13996
14081
|
// src/project-trust.ts
|
|
13997
14082
|
import { createInterface } from "node:readline/promises";
|
|
13998
14083
|
import { resolve as resolve3 } from "node:path";
|
|
13999
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
|
|
14000
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] ";
|
|
14001
14128
|
async function decideProjectTrust(cwd, agentDir, deps) {
|
|
14002
14129
|
if (!(deps.hasTrustRequiringResources ?? hasTrustRequiringProjectResources)(cwd))
|
|
@@ -14009,7 +14136,7 @@ async function decideProjectTrust(cwd, agentDir, deps) {
|
|
|
14009
14136
|
deps.log("This folder has project settings (.pi/ or .agents/skills); they are ignored because it is not trusted.");
|
|
14010
14137
|
return false;
|
|
14011
14138
|
}
|
|
14012
|
-
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());
|
|
14013
14140
|
store.set(cwd, decision);
|
|
14014
14141
|
return decision;
|
|
14015
14142
|
}
|
|
@@ -14063,6 +14190,9 @@ function catalogModelsFor(opts) {
|
|
|
14063
14190
|
return [{ id, name: id }];
|
|
14064
14191
|
}
|
|
14065
14192
|
function pickerModelName(opts, id) {
|
|
14193
|
+
if (id === ULTRAFAST_PICKER_ID) {
|
|
14194
|
+
return opts.models?.find((m) => m.id === ULTRAFAST_CATALOG_ID)?.name ?? ULTRAFAST_PICKER_ID;
|
|
14195
|
+
}
|
|
14066
14196
|
return [...catalogModelsFor(opts), ...defenseModelsFor(opts)].find((m) => m.id === id)?.name;
|
|
14067
14197
|
}
|
|
14068
14198
|
function defenseModelsFor(opts) {
|
|
@@ -14107,7 +14237,7 @@ function buildSettingsManager(opts, models, projectTrusted) {
|
|
|
14107
14237
|
quietStartup: true,
|
|
14108
14238
|
defaultThinkingLevel: "off",
|
|
14109
14239
|
hideThinkingBlock: true,
|
|
14110
|
-
tuiMode: "
|
|
14240
|
+
tuiMode: "fullscreen",
|
|
14111
14241
|
theme: "light/dark",
|
|
14112
14242
|
enableInstallTelemetry: false,
|
|
14113
14243
|
...compactionSettingsFor(opts.costArm) ? { compaction: compactionSettingsFor(opts.costArm) } : {}
|
|
@@ -14261,6 +14391,7 @@ function buildRuntimeOptions(opts, sessionId) {
|
|
|
14261
14391
|
});
|
|
14262
14392
|
const extensionFactories = [
|
|
14263
14393
|
providerExtension,
|
|
14394
|
+
...models.some((m) => m.id === ULTRAFAST_CATALOG_ID) ? [createUltrafastExtension(models.find((m) => m.id === ULTRAFAST_CATALOG_ID))] : [],
|
|
14264
14395
|
createFusionExtension(models[0].id, resolveFusionIds(models.map((m) => m.id), opts.fusion)),
|
|
14265
14396
|
adsExtension,
|
|
14266
14397
|
usageToolExtension,
|
|
@@ -14405,6 +14536,7 @@ async function launchPi(opts) {
|
|
|
14405
14536
|
});
|
|
14406
14537
|
installLogoutHandler(mode, { credentialsPath: opts.credentialsPath, isGuest: () => auth.isGuest() });
|
|
14407
14538
|
installModelAllowanceHandler(mode);
|
|
14539
|
+
installSafeUrlOpen(mode);
|
|
14408
14540
|
installFooterRightAlign(mode, () => {
|
|
14409
14541
|
const id = runtime.session?.model?.id;
|
|
14410
14542
|
return freeModelBase(pickerModelName(opts, id));
|
|
@@ -14425,8 +14557,8 @@ async function promptConsent(deps, text = CONSENT_TEXT) {
|
|
|
14425
14557
|
deps.log(NON_INTERACTIVE_CONSENT_TEXT);
|
|
14426
14558
|
return false;
|
|
14427
14559
|
}
|
|
14428
|
-
deps.log(text);
|
|
14429
|
-
const answer = await deps.askLine(CONSENT_PROMPT);
|
|
14560
|
+
deps.log(styleConsent(text));
|
|
14561
|
+
const answer = await deps.askLine(styleYesNo(CONSENT_PROMPT));
|
|
14430
14562
|
return parseConsentAnswer(answer);
|
|
14431
14563
|
}
|
|
14432
14564
|
async function promptConsentInteractive(text) {
|
|
@@ -14618,7 +14750,7 @@ function showIntro(log, env = process.env) {
|
|
|
14618
14750
|
if (introSkipped(env))
|
|
14619
14751
|
return;
|
|
14620
14752
|
log(`
|
|
14621
|
-
${INTRO_TEXT}
|
|
14753
|
+
${styleIntro(INTRO_TEXT)}
|
|
14622
14754
|
`);
|
|
14623
14755
|
}
|
|
14624
14756
|
var FIRST_TASK_EXPERIMENT = "retain.first_task";
|
|
@@ -14793,7 +14925,7 @@ async function promptSourceInteractive() {
|
|
|
14793
14925
|
const rl = createInterface3({ input: process.stdin, output: process.stdout });
|
|
14794
14926
|
try {
|
|
14795
14927
|
return await Promise.race([
|
|
14796
|
-
rl.question(SOURCE_QUESTION),
|
|
14928
|
+
rl.question(styleSourceQuestion(SOURCE_QUESTION)),
|
|
14797
14929
|
new Promise((resolve) => rl.once("close", () => resolve(undefined))),
|
|
14798
14930
|
new Promise((resolve) => rl.once("SIGINT", () => resolve("aborted")))
|
|
14799
14931
|
]);
|
|
@@ -15414,7 +15546,7 @@ ${HELP_TEXT}`);
|
|
|
15414
15546
|
homedir: homedir10(),
|
|
15415
15547
|
execPath: process.execPath,
|
|
15416
15548
|
autoUpdateEnabled: () => readAutoUpdate(getConfigPath()),
|
|
15417
|
-
spawn: (cmd, args, opts) =>
|
|
15549
|
+
spawn: (cmd, args, opts) => spawn4(cmd, args, opts),
|
|
15418
15550
|
proc: process,
|
|
15419
15551
|
log: (message) => console.log(message)
|
|
15420
15552
|
}),
|
package/package.json
CHANGED