Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
b36b17f
Add option to install context-lens
webwarrior-ws May 7, 2026
b2409fb
WIP: use npm to install context-lens only when pnpm is not available
webwarrior-ws May 21, 2026
c4c4d38
WIP: guarantee that context-lens dist is compiled if missing
knocte May 27, 2026
bff7dda
WIP: launch context-lens under current user, proxying to spi wrapper
knocte May 27, 2026
98b2530
WIP: simplify UI fallback to npm run build and check for missing ui/d…
knocte May 27, 2026
561e7b9
WIP: route HOME to agentUserHome for context-lens to find the agent s…
knocte May 27, 2026
7aa1781
WIP: forward proxy environment variables to sudo in spi launcher script
knocte May 27, 2026
ce9a936
WIP: increase check timeout to 45s, explain why in patch, and add exp…
knocte May 27, 2026
a8f11ee
WIP: relocate patches to patches/context-lens/ and update configurati…
webwarrior-ws Jun 16, 2026
445e020
Fixed format
knocte May 27, 2026
22e3d4f
WIP: clone context-lens repo as agent user
webwarrior-ws Jun 1, 2026
0a123d5
WIP: revert to original createLauncherScript func
webwarrior-ws Jun 1, 2026
9acb44d
WIP: detect if another context-lens is running
webwarrior-ws Jun 1, 2026
3dae4af
WIP: make context-lens capture reqs from extra instances
webwarrior-ws Jun 2, 2026
1206ab4
WIP: add PPQ costs patch
webwarrior-ws Jun 16, 2026
a50d10f
Revert "WIP: forward proxy environment variables to sudo in spi launc…
webwarrior-ws Jun 18, 2026
d807d60
WIP: don't use MITM proxy
webwarrior-ws Jun 18, 2026
78b3468
TMP: use awto-pi-lot from webwarrior-ws fork
webwarrior-ws Jun 18, 2026
c483e2e
WIP: don't reuse spi in cpi script
webwarrior-ws Jun 18, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 15 additions & 14 deletions ReadMe.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,20 +48,21 @@ npx skynot [options]

The following command‑line flags are available:

| Flag | Alias | Description |
|--------------|--------|-----------------------------------------------------------------------------------|
|`--help` | `-h` | Show the help message with all available options. |
|`--auth` | `-a` | Prompt for AI model's credentials to add env var to script or cook auth.json file.|
|`--extensions`| `-e` | DEPRECATED: Use `spi install <extension>` instead, after install. |
|`--git ["id"]`| `-g[i]`| Set git `user.name`/`user.email` for `aidev`. No arg: copies from current user. |
| | | With arg (e.g. `"Name Surname <user@example.com>"`): uses that instead. |
|`--npm` | `-n` | Install Pi using npm instead of tarball (likely to be slower though). |
|`--paranoid` | `-p` | Refrain from caching the sudo password; ask for it every time it is needed. |
|`--ssh` | `-s` | Copy SSH keys to the `aidev` user for git+ssh (& add GitHub to `known_hosts`). |
|`--update` | `-u` | Wipe any previous existing install of Pi and reinstall, to get the latest version.|
|`--verbose` | `-v` | Show more output from install commands (useful for debugging/low-bandwidth). |
|`--version` | `-V` | Output the version number. |
|`--destroy` |`--BURN`| Delete the `aidev` user, all its data (in `$HOME`), and the `aiteam` group. |
| Flag | Alias | Description |
|----------------|--------|-----------------------------------------------------------------------------------|
|`--help` | `-h` | Show the help message with all available options. |
|`--auth` | `-a` | Prompt for AI model's credentials to add env var to script or cook auth.json file.|
|`--extensions` | `-e` | DEPRECATED: Use `spi install <extension>` instead, after install. |
|`--git ["id"]` | `-g[i]`| Set git `user.name`/`user.email` for `aidev`. No arg: copies from current user. |
| | | With arg (e.g. `"Name Surname <user@example.com>"`): uses that instead. |
|`--npm` | `-n` | Install Pi using npm instead of tarball (likely to be slower though). |
|`--context-lens`| `-c` | Install context-lens and wrapper script `cpi` for launching pi with context-lens. |
|`--paranoid` | `-p` | Refrain from caching the sudo password; ask for it every time it is needed. |
|`--ssh` | `-s` | Copy SSH keys to the `aidev` user for git+ssh (& add GitHub to `known_hosts`). |
|`--update` | `-u` | Wipe any previous existing install of Pi and reinstall, to get the latest version.|
|`--verbose` | `-v` | Show more output from install commands (useful for debugging/low-bandwidth). |
|`--version` | `-V` | Output the version number. |
|`--destroy` |`--BURN`| Delete the `aidev` user, all its data (in `$HOME`), and the `aiteam` group. |


Please note, `-u` would technically not wipe or reinstall extensions, as they normally live in a different place (`.pi` subdir under `aidev` user's $HOME, and/or $NPM_CONFIG_PREFIX dir).
Expand Down
4 changes: 4 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@
"bin": {
"skynot": "bin/skynot"
},
"files": [
"dist/",
"patches/context-lens/"
],
"scripts": {
"dist": "mkdir -p bin && echo '#!/usr/bin/env node' > bin/skynot && echo \"require('../dist/index.js');\" >> bin/skynot && chmod +x bin/skynot",
"build": "npm install && npx tsc && npm run dist",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
From dd5612ad3c2ff8b1fbdaa7edf8e257c3242303f5 Mon Sep 17 00:00:00 2001
From: webwarrior-ws <reg@webwarrior.ws>
Date: Tue, 2 Jun 2026 13:51:13 +0200
Subject: [PATCH] Properly calculate costs when using PPQ.ai models

Use cost data from PPQ.ai API [1] to get token costs for PPQ
models. This does not take caching into account because such
info is not present in [1].

Fixes https://github.com/larsderidder/context-lens/issues/60

[1] https://api.ppq.ai/v1/models
---
src/server/store.ts | 70 ++++++++++++++++++++++++++++++++++++++++++---
1 file changed, 66 insertions(+), 4 deletions(-)

diff --git a/src/server/store.ts b/src/server/store.ts
index 1afc3c5..6742964 100644
--- a/src/server/store.ts
+++ b/src/server/store.ts
@@ -54,6 +54,50 @@ type StoreChangeListener = (event: StoreChangeEvent) => void;
const CODEX_SESSION_TTL_MS = 5 * 60 * 1000;
const GEMINI_SESSION_TTL_MS = 5 * 60 * 1000;

+interface PpqPricing {
+ input_per_1M_tokens: number;
+ output_per_1M_tokens: number;
+}
+
+interface PpqModelsData {
+ data: [
+ {
+ id: string;
+ pricing: PpqPricing;
+ },
+ ];
+}
+
+class PpqPricingData {
+ private static instance: PpqPricingData | null = null;
+ private data: Map<string, PpqPricing> = new Map();
+
+ private constructor(modelsData: PpqModelsData) {
+ for (const model of modelsData.data) {
+ // PPQ API uses price of -1 for automatic models. Ignore them to not have negative costs.
+ if (
+ model.pricing.input_per_1M_tokens > 0 &&
+ model.pricing.output_per_1M_tokens > 0
+ ) {
+ this.data.set(model.id, model.pricing);
+ }
+ }
+ }
+
+ public static async getInstance(): Promise<PpqPricingData> {
+ if (!PpqPricingData.instance) {
+ const response = await fetch("https://api.ppq.ai/v1/models");
+ const json = await response.json();
+ PpqPricingData.instance = new PpqPricingData(json as PpqModelsData);
+ }
+ return PpqPricingData.instance;
+ }
+
+ public getPricing(model: string): PpqPricing | undefined {
+ return this.data.get(model);
+ }
+}
+
export class Store {
private readonly dataDir: string;
private readonly stateFile: string;
@@ -87,6 +131,9 @@ export class Store {
// Tags storage
private tagsStore: TagsStore;

+ // PPQ pricing data. Fetched from PPQ API when Store is created.
+ private ppqPricingData: PpqPricingData | undefined;
+
constructor(opts: {
dataDir: string;
stateFile: string;
@@ -113,6 +160,10 @@ export class Store {
}

this.tagsStore = new TagsStore(this.dataDir);
+
+ PpqPricingData.getInstance().then((instance) => {
+ this.ppqPricingData = instance;
+ });
}

getRevision(): number {
@@ -431,15 +482,26 @@ export class Store {
httpStatus === null || (httpStatus >= 200 && httpStatus < 300);
const inputTok = usage.inputTokens || contextInfo.totalTokens;
const outputTok = usage.outputTokens;
- const costUsd = isSuccessResponse
- ? estimateCost(
+ let costUsd: number | null = 0;
+ if (isSuccessResponse) {
+ if (meta?.targetUrl?.includes("ppq.ai")) {
+ const pricing = this.ppqPricingData?.getPricing(contextInfo.model);
+ if (pricing) {
+ costUsd =
+ (inputTok * pricing.input_per_1M_tokens +
+ outputTok * pricing.output_per_1M_tokens) /
+ 1000000;
+ }
+ } else {
+ costUsd = estimateCost(
contextInfo.model,
inputTok,
outputTok,
usage.cacheReadTokens,
usage.cacheWriteTokens,
- )
- : 0;
+ );
+ }
+ }

const entry: CapturedEntry = {
id: this.nextEntryId++,
--
2.54.0

Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
From a1e0e854fa6a12db7cfcb32ef8a1c86fbaddab7d Mon Sep 17 00:00:00 2001
From: Skynot Assistant <helper@skynot.ws>
Date: Wed, 27 May 2026 14:10:00 +0200
Subject: [PATCH] Increase no-traffic warning timeout to 45 seconds

It might take a while for Pi to start up and make its first requests if some of
your loaded extensions gather metadata or custom model details from APIs on start.
---
src/cli.ts | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/cli.ts b/src/cli.ts
index c479f07..d471dfc 100644
--- a/src/cli.ts
+++ b/src/cli.ts
@@ -704,7 +704,7 @@ if (parsedArgs.commandName === "analyze") {
);
req.on("error", () => {});
req.on("timeout", () => req.destroy());
- }, 15_000);
+ }, 45_000);
}
}

--
2.54.0
Loading