@north-light/cli 0.3.551 → 0.3.553
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/api/client.d.ts +11 -0
- package/dist/api/client.js +3 -3
- package/dist/api/contract.d.ts +1 -1
- package/dist/api/contract.js +1 -1
- package/dist/api/dto/charges.d.ts +122 -0
- package/dist/api/dto/charges.js +0 -0
- package/dist/api/dto/usage.d.ts +3 -3
- package/dist/api/index.d.ts +1 -0
- package/dist/api/index.js +1 -1
- package/dist/api/routes.d.ts +3 -0
- package/dist/api/routes.js +1 -1
- package/dist/builtin-memory/crouter-sdk/release-notes.md +10 -0
- package/dist/clients/attach/viewer.js +50 -50
- package/dist/commands/sys/spend.d.ts +1 -0
- package/dist/commands/sys/spend.js +3 -0
- package/dist/commands/sys.js +1 -1
- package/dist/core/canvas/canvas.js +4 -4
- package/dist/core/canvas/db.js +4 -4
- package/dist/core/canvas/export-sqlite.js +2 -2
- package/dist/core/canvas/import-sqlite.d.ts +2 -0
- package/dist/core/canvas/import-sqlite.js +4 -4
- package/dist/core/canvas/person.js +7 -16
- package/dist/core/canvas/schema-chain.d.ts +34 -0
- package/dist/core/canvas/schema-chain.js +1 -0
- package/dist/core/canvas/schema-pg/.gitkeep +0 -0
- package/dist/core/canvas/schema-pg.sql +61 -0
- package/dist/core/canvas/schema-version.d.ts +29 -3
- package/dist/core/canvas/schema-version.js +1 -1
- package/dist/core/canvas/types.d.ts +4 -0
- package/dist/core/config.js +1 -1
- package/dist/core/grants/mirror.d.ts +2 -1
- package/dist/core/grants/mirror.js +2 -2
- package/dist/core/ledger/backfill.d.ts +12 -0
- package/dist/core/ledger/backfill.js +22 -0
- package/dist/core/ledger/charges.d.ts +18 -0
- package/dist/core/ledger/charges.js +1 -0
- package/dist/core/ledger/check.d.ts +44 -0
- package/dist/core/ledger/check.js +7 -0
- package/dist/core/ledger/index.d.ts +9 -0
- package/dist/core/ledger/index.js +1 -0
- package/dist/core/ledger/limits.d.ts +15 -0
- package/dist/core/ledger/limits.js +3 -0
- package/dist/core/ledger/months.d.ts +6 -0
- package/dist/core/ledger/months.js +1 -0
- package/dist/core/ledger/payer.d.ts +34 -0
- package/dist/core/ledger/payer.js +1 -0
- package/dist/core/ledger/read.d.ts +44 -0
- package/dist/core/ledger/read.js +3 -0
- package/dist/core/ledger/totals.d.ts +19 -0
- package/dist/core/ledger/totals.js +4 -0
- package/dist/core/ledger/types.d.ts +66 -0
- package/dist/core/ledger/types.js +0 -0
- package/dist/core/llm/run.d.ts +17 -5
- package/dist/core/llm/run.js +2 -2
- package/dist/core/providers/call.d.ts +7 -1
- package/dist/core/providers/call.js +1 -1
- package/dist/core/providers/errors.js +1 -1
- package/dist/core/providers/receipts.d.ts +7 -1
- package/dist/core/providers/receipts.js +1 -3
- package/dist/core/runs/operations.d.ts +1 -0
- package/dist/core/runs/operations.js +7 -7
- package/dist/core/runtime/broker/cli-relay.js +1 -1
- package/dist/core/runtime/broker/model-adapter.js +2 -2
- package/dist/core/runtime/broker/turn-cause.d.ts +7 -0
- package/dist/core/runtime/broker/turn-cause.js +1 -0
- package/dist/core/runtime/broker.js +1 -1
- package/dist/core/runtime/nodes.d.ts +2 -0
- package/dist/core/runtime/nodes.js +1 -1
- package/dist/core/runtime/recycle.js +1 -1
- package/dist/core/runtime/reset.js +1 -1
- package/dist/core/runtime/revive.js +2 -2
- package/dist/core/runtime/spawn.d.ts +2 -0
- package/dist/core/runtime/spawn.js +2 -2
- package/dist/core/runtime/start-check.d.ts +15 -0
- package/dist/core/runtime/start-check.js +1 -0
- package/dist/core/runtime/warm-pool.js +1 -1
- package/dist/core/user-settings.d.ts +4 -0
- package/dist/core/user-settings.js +1 -1
- package/dist/daemon/api/app-listener.js +13 -13
- package/dist/daemon/api/handlers/bash-jobs.js +1 -1
- package/dist/daemon/api/handlers/charges.d.ts +3 -0
- package/dist/daemon/api/handlers/charges.js +1 -0
- package/dist/daemon/api/handlers/llm.d.ts +9 -5
- package/dist/daemon/api/handlers/llm.js +3 -3
- package/dist/daemon/api/handlers/messages.js +2 -2
- package/dist/daemon/api/handlers/providers.d.ts +2 -0
- package/dist/daemon/api/handlers/providers.js +1 -1
- package/dist/daemon/api/handlers/run-routes.js +1 -1
- package/dist/daemon/api/handlers/runs.d.ts +1 -1
- package/dist/daemon/api/handlers/runs.js +1 -1
- package/dist/daemon/api/operations.js +1 -1
- package/dist/daemon/api/router.d.ts +8 -0
- package/dist/daemon/api/router.js +1 -1
- package/dist/daemon/api/server.js +1 -1
- package/dist/daemon/cron/authority.d.ts +1 -1
- package/dist/daemon/cron-run.js +2 -2
- package/dist/daemon/crtrd.js +10 -10
- package/dist/daemon/fleet.js +4 -4
- package/dist/daemon/reconcilers/action-lane.js +1 -1
- package/dist/daemon/reconcilers/node-lifecycle/freeze-lane.d.ts +2 -0
- package/dist/daemon/reconcilers/node-lifecycle/freeze-lane.js +1 -1
- package/dist/types.d.ts +4 -0
- package/docs/sdk/release-notes.md +10 -0
- package/package.json +3 -2
- package/packages/crouter-identity/package.json +1 -1
- package/runtime.lock.json +13 -13
- package/scripts/install-runtime.mjs +6 -20
- package/scripts/lib/canvas-schema-gate.mjs +20 -0
- package/dist/core/usage/ledger.d.ts +0 -49
- package/dist/core/usage/ledger.js +0 -10
package/runtime.lock.json
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@north-light/cli",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.553",
|
|
4
4
|
"lockfileVersion": 3,
|
|
5
5
|
"requires": true,
|
|
6
6
|
"packages": {
|
|
7
7
|
"": {
|
|
8
8
|
"name": "@north-light/cli",
|
|
9
|
-
"version": "0.3.
|
|
9
|
+
"version": "0.3.553",
|
|
10
10
|
"hasInstallScript": true,
|
|
11
11
|
"license": "UNLICENSED",
|
|
12
12
|
"workspaces": [
|
|
@@ -24,7 +24,7 @@
|
|
|
24
24
|
"@milkdown/preset-gfm": "^7.22.3",
|
|
25
25
|
"@milkdown/prose": "^7.22.3",
|
|
26
26
|
"@milkdown/utils": "^7.22.3",
|
|
27
|
-
"@north-light/identity": "0.3.
|
|
27
|
+
"@north-light/identity": "0.3.553",
|
|
28
28
|
"cron-parser": "^5.6.0",
|
|
29
29
|
"esbuild": "^0.27.7",
|
|
30
30
|
"jose": "^6.2.12",
|
|
@@ -12455,17 +12455,17 @@
|
|
|
12455
12455
|
},
|
|
12456
12456
|
"packages/crouter-api": {
|
|
12457
12457
|
"name": "@north-light/api",
|
|
12458
|
-
"version": "0.3.
|
|
12458
|
+
"version": "0.3.553",
|
|
12459
12459
|
"license": "UNLICENSED"
|
|
12460
12460
|
},
|
|
12461
12461
|
"packages/crouter-env-docker": {
|
|
12462
12462
|
"name": "@north-light/env-docker",
|
|
12463
|
-
"version": "0.3.
|
|
12463
|
+
"version": "0.3.553",
|
|
12464
12464
|
"license": "UNLICENSED"
|
|
12465
12465
|
},
|
|
12466
12466
|
"packages/crouter-identity": {
|
|
12467
12467
|
"name": "@north-light/identity",
|
|
12468
|
-
"version": "0.3.
|
|
12468
|
+
"version": "0.3.553",
|
|
12469
12469
|
"license": "UNLICENSED",
|
|
12470
12470
|
"dependencies": {
|
|
12471
12471
|
"jose": "^6.2.1"
|
|
@@ -12473,21 +12473,21 @@
|
|
|
12473
12473
|
},
|
|
12474
12474
|
"packages/crouter-plugin": {
|
|
12475
12475
|
"name": "@north-light/plugin",
|
|
12476
|
-
"version": "0.3.
|
|
12476
|
+
"version": "0.3.553",
|
|
12477
12477
|
"license": "UNLICENSED",
|
|
12478
12478
|
"dependencies": {
|
|
12479
|
-
"@north-light/api": "0.3.
|
|
12480
|
-
"@north-light/identity": "0.3.
|
|
12479
|
+
"@north-light/api": "0.3.553",
|
|
12480
|
+
"@north-light/identity": "0.3.553"
|
|
12481
12481
|
}
|
|
12482
12482
|
},
|
|
12483
12483
|
"packages/crouter-sdk": {
|
|
12484
12484
|
"name": "@north-light/sdk",
|
|
12485
|
-
"version": "0.3.
|
|
12485
|
+
"version": "0.3.553",
|
|
12486
12486
|
"license": "UNLICENSED",
|
|
12487
12487
|
"dependencies": {
|
|
12488
|
-
"@north-light/api": "0.3.
|
|
12489
|
-
"@north-light/identity": "0.3.
|
|
12490
|
-
"@north-light/plugin": "0.3.
|
|
12488
|
+
"@north-light/api": "0.3.553",
|
|
12489
|
+
"@north-light/identity": "0.3.553",
|
|
12490
|
+
"@north-light/plugin": "0.3.553",
|
|
12491
12491
|
"jose": "^6.2.1"
|
|
12492
12492
|
},
|
|
12493
12493
|
"bin": {
|
|
@@ -13,6 +13,7 @@ import { smokeValidate } from './runtime-smoke.mjs';
|
|
|
13
13
|
import { scrubInheritedBrokerEnv, unsafeIsolationReason } from './lib/isolation-env.mjs';
|
|
14
14
|
import { packArgs } from './lib/pack-args.mjs';
|
|
15
15
|
import { runtimeDepsKeyFromFiles } from './lib/runtime-deps-key.mjs';
|
|
16
|
+
import { assertCandidateMayOpenLiveDatabase, candidateSchemaVersion } from './lib/canvas-schema-gate.mjs';
|
|
16
17
|
|
|
17
18
|
scrubInheritedBrokerEnv();
|
|
18
19
|
// CI has no account store to protect, and its checkout sits inside the runner's
|
|
@@ -198,18 +199,11 @@ async function assertCanvasSchemaCompatible(stage) {
|
|
|
198
199
|
}
|
|
199
200
|
}
|
|
200
201
|
|
|
201
|
-
/**
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
if (!Number.isSafeInteger(version) || version < 1) throw new Error('candidate runtime does not expose a valid canvas schema version');
|
|
205
|
-
return version;
|
|
206
|
-
}
|
|
207
|
-
|
|
208
|
-
/** Read `canvas_meta.schema_version` from the live Postgres cluster and refuse a candidate older than it. A cluster that
|
|
209
|
-
* is not running cannot be read, so the candidate is refused until the cluster is started. */
|
|
202
|
+
/** Refuse a candidate whose version is below `canvas_meta.schema_min_reader` (absent: `schema_version`) in the live Postgres
|
|
203
|
+
* cluster, read from `CRTR_DATABASE_SCHEMA` as the daemon reads it (`scripts/lib/canvas-schema-gate.mjs`). A cluster that is
|
|
204
|
+
* not running cannot be read, so the candidate is refused until the cluster is started. */
|
|
210
205
|
async function assertPostgresSchemaCompatible(stage, runtime) {
|
|
211
206
|
const { default: pg } = await import('pg');
|
|
212
|
-
const supported = await candidatePostgresSchemaVersion(stage);
|
|
213
207
|
let socketDir = join(runtime, 'pg');
|
|
214
208
|
try { socketDir = (await readFile(join(runtime, 'pg', 'socket-dir'), 'utf8')).trim(); } catch (error) { if (error?.code !== 'ENOENT') throw error; }
|
|
215
209
|
const connectionString = process.env.CRTR_DATABASE_URL
|
|
@@ -220,22 +214,14 @@ async function assertPostgresSchemaCompatible(stage, runtime) {
|
|
|
220
214
|
} catch (error) {
|
|
221
215
|
if (!process.env.CRTR_DATABASE_URL && (error?.code === 'ENOENT' || error?.code === 'ECONNREFUSED')) {
|
|
222
216
|
throw new Error(
|
|
223
|
-
`refusing to select runtime: the Postgres cluster at ${socketDir} is not running, so its canvas schema version cannot be checked against this build (${
|
|
217
|
+
`refusing to select runtime: the Postgres cluster at ${socketDir} is not running, so its canvas schema version cannot be checked against this build (${await candidateSchemaVersion(stage)}). ` +
|
|
224
218
|
'Start it with the currently selected generation (`crtr sys daemon start`) and install again.',
|
|
225
219
|
);
|
|
226
220
|
}
|
|
227
221
|
throw error;
|
|
228
222
|
}
|
|
229
223
|
try {
|
|
230
|
-
|
|
231
|
-
const row = exists.rows[0].t === null ? { rows: [] } : await client.query(`SELECT value FROM canvas_meta WHERE key = 'schema_version'`);
|
|
232
|
-
const current = row.rows[0] === undefined ? undefined : Number(row.rows[0].value);
|
|
233
|
-
if (current !== undefined && current > supported) {
|
|
234
|
-
throw new Error(
|
|
235
|
-
`refusing to select runtime with canvas schema ${supported}: ` +
|
|
236
|
-
`the live database is already at version ${current}; install a descendant build instead`,
|
|
237
|
-
);
|
|
238
|
-
}
|
|
224
|
+
await assertCandidateMayOpenLiveDatabase(stage, client);
|
|
239
225
|
} finally {
|
|
240
226
|
await client.end();
|
|
241
227
|
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
// The installer's rollback gate on the live Postgres canvas: loads the candidate generation's own schema module (its
|
|
2
|
+
// supported version, which Postgres schema holds the canvas — `CRTR_DATABASE_SCHEMA`, read by the same resolver the daemon
|
|
3
|
+
// uses — and the check itself) and refuses a candidate below the database's `schema_min_reader`. Takes a connected client so
|
|
4
|
+
// a test can drive it without the installer's side effects.
|
|
5
|
+
import { join } from 'node:path';
|
|
6
|
+
import { pathToFileURL } from 'node:url';
|
|
7
|
+
|
|
8
|
+
/** `client` is a connected `pg` client for the live database; `env` is the installer's environment. */
|
|
9
|
+
export async function assertCandidateMayOpenLiveDatabase(stage, client, env = process.env) {
|
|
10
|
+
const candidate = await import(pathToFileURL(join(stage, 'dist', 'core', 'canvas', 'schema-version.js')).href);
|
|
11
|
+
const supported = candidate.CANVAS_SCHEMA_VERSION;
|
|
12
|
+
if (!Number.isSafeInteger(supported) || supported < 1) throw new Error('candidate runtime does not expose a valid canvas schema version');
|
|
13
|
+
await candidate.assertCandidateMayOpen(client, supported, candidate.canvasDatabaseSchema(env));
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/** The candidate's supported canvas schema version, for messages. */
|
|
17
|
+
export async function candidateSchemaVersion(stage) {
|
|
18
|
+
const candidate = await import(pathToFileURL(join(stage, 'dist', 'core', 'canvas', 'schema-version.js')).href);
|
|
19
|
+
return candidate.CANVAS_SCHEMA_VERSION;
|
|
20
|
+
}
|
|
@@ -1,49 +0,0 @@
|
|
|
1
|
-
import { type CanvasDb } from '../canvas/db.js';
|
|
2
|
-
import type { SpendUsageDTO } from '../../api/dto/usage.js';
|
|
3
|
-
/** The person's own agent. Its grant carries the directory's default cap, but the
|
|
4
|
-
* cap bounds what an app spends of the person's subscription, never the person's
|
|
5
|
-
* own work, so `app:terminal` is never stopped. */
|
|
6
|
-
export declare const UNCAPPED_GRANTEE = "app:terminal";
|
|
7
|
-
export type Payer = 'user' | 'app';
|
|
8
|
-
/** The UTC calendar month `YYYY-MM` of `at`. */
|
|
9
|
-
export declare function usageMonth(at?: Date): string;
|
|
10
|
-
/** 00:00Z on the first day of the UTC month after `month`. */
|
|
11
|
-
export declare function resetAt(month: string): string;
|
|
12
|
-
export interface UsageRecord {
|
|
13
|
-
grantee: string;
|
|
14
|
-
payer: Payer;
|
|
15
|
-
/** `model` for a completion, `provider:<id>` for a provider receipt. */
|
|
16
|
-
source: string;
|
|
17
|
-
/** The model that answered; `''` for a provider receipt. */
|
|
18
|
-
served_model: string;
|
|
19
|
-
input_tokens: number;
|
|
20
|
-
output_tokens: number;
|
|
21
|
-
cached_tokens: number;
|
|
22
|
-
/** List-price cost; null when the served model has no list price (it adds nothing to the total). */
|
|
23
|
-
usd_equivalent: number | null;
|
|
24
|
-
}
|
|
25
|
-
/** Add one completion's or receipt's usage to its grantee's month, inside the caller's write. */
|
|
26
|
-
export declare function addUsage(db: CanvasDb, record: UsageRecord, at?: Date): Promise<void>;
|
|
27
|
-
/** Record one model completion for `grantee`. */
|
|
28
|
-
export declare function recordModelUsage(grantee: string, payer: Payer, servedModel: string, usage: {
|
|
29
|
-
input: number;
|
|
30
|
-
output: number;
|
|
31
|
-
cacheRead: number;
|
|
32
|
-
}, usdEquivalent: number | null): Promise<void>;
|
|
33
|
-
/** The grantee's user-paid month-to-date model spend; provider receipts are not in it. */
|
|
34
|
-
export declare function monthSpend(grantee: string, month?: string): Promise<number>;
|
|
35
|
-
/** Who a user-paid call bills, and the cap that bounds it (`null` = uncapped). */
|
|
36
|
-
export interface SpendTarget {
|
|
37
|
-
grantee: string;
|
|
38
|
-
spend_cap: number | null;
|
|
39
|
-
}
|
|
40
|
-
/** The cap that applies to `target`: none for the person's own agent or a grant with no cap. */
|
|
41
|
-
export declare function effectiveCap(target: SpendTarget): number | null;
|
|
42
|
-
/** Refuse a user-paid call once the grantee's month spend reached its cap (SPD-2).
|
|
43
|
-
* The check runs before the call; one response may overshoot the cap (no
|
|
44
|
-
* reserve-then-settle), and the next call is refused. */
|
|
45
|
-
export declare function assertUnderCap(target: SpendTarget | undefined, at?: Date): Promise<void>;
|
|
46
|
-
/** `usage.get` for one grantee and month. */
|
|
47
|
-
export declare function usageFor(grantee: string, spendCap: number | null, month?: string): Promise<SpendUsageDTO>;
|
|
48
|
-
/** A `month` query value: `YYYY-MM` with a real month, years 1000-9999; absent means the current month. */
|
|
49
|
-
export declare function parseUsageMonth(value: string | null): string;
|
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
var f=Object.defineProperty;var a=(e,t)=>f(e,"name",{value:t,configurable:!0});import{withCanvasWrite as h,openDb as d}from"../canvas/db.js";import{RunError as _}from"../runs/operations.js";const q="app:terminal";function r(e=new Date){return e.toISOString().slice(0,7)}a(r,"usageMonth");function l(e){const[t,n]=e.split("-").map(Number);return new Date(Date.UTC(t,n,1)).toISOString()}a(l,"resetAt");async function w(e,t,n=new Date){const u=r(n);await e.prepare(`INSERT INTO usage (grantee, month, payer, source, served_model, input_tokens, output_tokens, cached_tokens, usd_equivalent)
|
|
2
|
-
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
3
|
-
ON CONFLICT(grantee, month, payer, source, served_model) DO UPDATE SET
|
|
4
|
-
input_tokens = usage.input_tokens + excluded.input_tokens,
|
|
5
|
-
output_tokens = usage.output_tokens + excluded.output_tokens,
|
|
6
|
-
cached_tokens = usage.cached_tokens + excluded.cached_tokens,
|
|
7
|
-
usd_equivalent = CASE WHEN usage.usd_equivalent IS NULL AND excluded.usd_equivalent IS NULL THEN NULL
|
|
8
|
-
ELSE COALESCE(usage.usd_equivalent, 0) + COALESCE(excluded.usd_equivalent, 0) END`).run(t.grantee,u,t.payer,t.source,t.served_model,t.input_tokens,t.output_tokens,t.cached_tokens,t.usd_equivalent),t.payer==="user"&&t.source==="model"&&t.usd_equivalent!==null&&t.usd_equivalent>0&&await e.prepare(`INSERT INTO grantee_usage (grantee, month, usd_equivalent) VALUES (?, ?, ?)
|
|
9
|
-
ON CONFLICT(grantee, month) DO UPDATE SET usd_equivalent = grantee_usage.usd_equivalent + excluded.usd_equivalent`).run(t.grantee,u,t.usd_equivalent)}a(w,"addUsage");async function y(e,t,n,u,s){await h(async p=>await w(p,{grantee:e,payer:t,source:"model",served_model:n,input_tokens:u.input,output_tokens:u.output,cached_tokens:u.cacheRead,usd_equivalent:s}))}a(y,"recordModelUsage");async function c(e,t=r()){return(await(await d()).prepare("SELECT usd_equivalent FROM grantee_usage WHERE grantee = ? AND month = ?").get(e,t))?.usd_equivalent??0}a(c,"monthSpend");function m(e){return e.grantee===q?null:e.spend_cap}a(m,"effectiveCap");async function x(e,t=new Date){if(!e)return;const n=m(e);if(n===null)return;const u=r(t),s=await c(e.grantee,u);if(!(s<n))throw new _(402,"cap_exhausted",`${e.grantee} reached its monthly usage limit`,void 0,{spend_cap:n,usd_equivalent:s,reset_at:l(u)})}a(x,"assertUnderCap");async function C(e,t,n=r()){const u=await(await d()).prepare(`SELECT payer, source, served_model, input_tokens, output_tokens, usd_equivalent
|
|
10
|
-
FROM usage WHERE grantee = ? AND month = ? ORDER BY served_model`).all(e,n),s=a(i=>u.filter(o=>o.payer===i&&o.source==="model").map(({served_model:o,input_tokens:E,output_tokens:v,usd_equivalent:g})=>({served_model:o,input_tokens:E,output_tokens:v,usd_equivalent:g})),"byModel"),p=u.filter(i=>i.payer==="app").reduce((i,o)=>i+(o.usd_equivalent??0),0);return{grantee:e,month:n,usd_equivalent:await c(e,n),by_model:s("user"),app_paid:{usd_equivalent:p,by_model:s("app")},spend_cap:m({grantee:e,spend_cap:t}),reset_at:l(n)}}a(C,"usageFor");function D(e){if(e===null)return r();if(!/^[1-9]\d{3}-(0[1-9]|1[0-2])$/.test(e))throw new _(400,"invalid_request","month must be YYYY-MM","month");return e}a(D,"parseUsageMonth");export{q as UNCAPPED_GRANTEE,w as addUsage,x as assertUnderCap,m as effectiveCap,c as monthSpend,D as parseUsageMonth,y as recordModelUsage,l as resetAt,C as usageFor,r as usageMonth};
|