@hasna/economy 0.3.27 → 0.4.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/CHANGELOG.md +101 -0
- package/CONTRIBUTING.md +1 -1
- package/README.md +9 -16
- package/SECURITY.md +1 -1
- package/dist/cli/commands/extras.d.ts.map +1 -1
- package/dist/cli/index.js +1182 -862
- package/dist/db/cloud.d.ts +16 -8
- package/dist/db/cloud.d.ts.map +1 -1
- package/dist/db/database.d.ts +58 -0
- package/dist/db/database.d.ts.map +1 -1
- package/dist/index.js +236 -27
- package/dist/ingest/claude.d.ts.map +1 -1
- package/dist/ingest/loops.d.ts +19 -0
- package/dist/ingest/loops.d.ts.map +1 -1
- package/dist/lib/accounts-store.d.ts +83 -0
- package/dist/lib/accounts-store.d.ts.map +1 -0
- package/dist/lib/accounts.d.ts +2 -1
- package/dist/lib/accounts.d.ts.map +1 -1
- package/dist/lib/api-display-url.d.ts +19 -0
- package/dist/lib/api-display-url.d.ts.map +1 -0
- package/dist/lib/autosync-gate.d.ts +15 -0
- package/dist/lib/autosync-gate.d.ts.map +1 -0
- package/dist/lib/cloud-ingest.d.ts +15 -1
- package/dist/lib/cloud-ingest.d.ts.map +1 -1
- package/dist/lib/cloud-storage.d.ts +166 -10
- package/dist/lib/cloud-storage.d.ts.map +1 -1
- package/dist/lib/gatherer.d.ts.map +1 -1
- package/dist/lib/model-config.d.ts +1 -1
- package/dist/lib/model-config.d.ts.map +1 -1
- package/dist/lib/serve-auth.d.ts.map +1 -1
- package/dist/lib/store/index.d.ts +6 -3
- package/dist/lib/store/index.d.ts.map +1 -1
- package/dist/lib/test-hermetic-accounts.d.ts +3 -2
- package/dist/lib/test-hermetic-accounts.d.ts.map +1 -1
- package/dist/lib/test-hermetic-fleet-env.d.ts +4 -0
- package/dist/lib/test-hermetic-fleet-env.d.ts.map +1 -0
- package/dist/mcp/agent-registry.d.ts +85 -0
- package/dist/mcp/agent-registry.d.ts.map +1 -0
- package/dist/mcp/harness.d.ts +26 -0
- package/dist/mcp/harness.d.ts.map +1 -0
- package/dist/mcp/index.js +1387 -311
- package/dist/mcp/server.d.ts.map +1 -1
- package/dist/otel/index.js +468 -24
- package/dist/server/index.js +595 -164
- package/dist/server/serve.d.ts +0 -2
- package/dist/server/serve.d.ts.map +1 -1
- package/docs/cli.md +2 -3
- package/docs/configuration.md +23 -10
- package/docs/ingestion.md +1 -1
- package/docs/mcp.md +4 -2
- package/docs/otel.md +8 -2
- package/docs/rest-api.md +2 -2
- package/package.json +7 -11
- package/postinstall.js +82 -0
- package/dashboard/README.md +0 -26
- package/dist/cli/brains.d.ts +0 -3
- package/dist/cli/brains.d.ts.map +0 -1
package/dist/db/cloud.d.ts
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import type { AuthQueryClient } from '@hasna/contracts/auth';
|
|
2
|
-
import type { ServerDataBackend } from '@hasna/contracts/schemas';
|
|
3
2
|
import pg from 'pg';
|
|
4
3
|
import type { DbAdapter, SqliteAdapter as Database } from './sqlite-adapter.js';
|
|
5
4
|
/** The environment shape the backend resolver reads. */
|
|
@@ -9,18 +8,27 @@ export declare function getCloudDatabaseUrl(env?: Env): string | undefined;
|
|
|
9
8
|
/**
|
|
10
9
|
* Resolve the server data backend from database configuration ALONE.
|
|
11
10
|
*
|
|
12
|
-
* `@hasna/contracts` 0.
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
11
|
+
* `@hasna/contracts` 1.0.2 narrowed its published `ServerDataBackendSchema` to
|
|
12
|
+
* `z.literal("postgresql")` — SQLite is legacy-import input, never a LIVE
|
|
13
|
+
* backend, so the contract's health vocabulary only speaks the authoritative
|
|
14
|
+
* arm. Economy's serve still runs a real on-box SQLite backend in local mode,
|
|
15
|
+
* so the resolver keeps its own two-arm union and the runtime reports the
|
|
16
|
+
* honest backend on `/health` (the contract schema is asserted against the
|
|
17
|
+
* postgresql arm in `foundation-probe.contract.test.ts`).
|
|
18
|
+
*
|
|
19
|
+
* The retired deployment-mode axis stays gone: the only switch is the server's
|
|
20
|
+
* data backend, `sqlite | postgresql`, and a present database URL is what
|
|
21
|
+
* selects `postgresql`. Retired `STORAGE_MODE` / `MODE` variables are rejected
|
|
22
|
+
* with a migration hint rather than normalized or silently mapped, so a
|
|
23
|
+
* half-migrated deployment fails loudly at startup instead of quietly serving
|
|
24
|
+
* the wrong store.
|
|
18
25
|
*
|
|
19
26
|
* The rejection stays local because economy also honours the bare `DATABASE_URL`
|
|
20
27
|
* alias, which the contract's own resolver does not read — deferring to it
|
|
21
28
|
* wholesale would silently downgrade such a deployment to sqlite.
|
|
22
29
|
*/
|
|
23
|
-
export
|
|
30
|
+
export type EconomyServerBackend = 'sqlite' | 'postgresql';
|
|
31
|
+
export declare function resolveEconomyServerBackend(env?: Env): EconomyServerBackend;
|
|
24
32
|
/** True when the serve reads and writes PostgreSQL directly. */
|
|
25
33
|
export declare function isPostgresBackend(env?: Env): boolean;
|
|
26
34
|
/** HMAC signing secret for API-key verification (server-held, never in a token). */
|
package/dist/db/cloud.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cloud.d.ts","sourceRoot":"","sources":["../../src/db/cloud.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAA;AAC5D,OAAO,
|
|
1
|
+
{"version":3,"file":"cloud.d.ts","sourceRoot":"","sources":["../../src/db/cloud.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAA;AAC5D,OAAO,EAAE,MAAM,IAAI,CAAA;AACnB,OAAO,KAAK,EAAE,SAAS,EAAE,aAAa,IAAI,QAAQ,EAAE,MAAM,qBAAqB,CAAA;AAK/E,wDAAwD;AACxD,KAAK,GAAG,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAAA;AAqB7C,8DAA8D;AAC9D,wBAAgB,mBAAmB,CAAC,GAAG,GAAE,GAAiB,GAAG,MAAM,GAAG,SAAS,CAO9E;AAED;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,MAAM,MAAM,oBAAoB,GAAG,QAAQ,GAAG,YAAY,CAAA;AAE1D,wBAAgB,2BAA2B,CAAC,GAAG,GAAE,GAAiB,GAAG,oBAAoB,CAGxF;AAED,gEAAgE;AAChE,wBAAgB,iBAAiB,CAAC,GAAG,GAAE,GAAiB,GAAG,OAAO,CAEjE;AAED,oFAAoF;AACpF,wBAAgB,oBAAoB,IAAI,MAAM,GAAG,SAAS,CAOzD;AAED;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,GAAG,qBAAwB,GAAG,QAAQ,CASvE;AAED,0EAA0E;AAC1E,wBAAgB,eAAe,CAAC,GAAG,qBAAwB,GAAG,EAAE,CAAC,IAAI,CAWpE;AAED;;;;GAIG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,GAAG,eAAe,CAcjE;AAED,+EAA+E;AAC/E,wBAAgB,eAAe,IAAI,MAAM,EAAE,CAE1C;AAED,YAAY,EAAE,SAAS,EAAE,CAAA"}
|
package/dist/db/database.d.ts
CHANGED
|
@@ -1,6 +1,56 @@
|
|
|
1
1
|
import { SqliteAdapter as Database } from './sqlite-adapter.js';
|
|
2
|
+
export type PathKind = "config" | "data" | "state" | "cache";
|
|
3
|
+
export interface PathsResolverOptions {
|
|
4
|
+
app: string;
|
|
5
|
+
internal?: boolean;
|
|
6
|
+
platform?: string;
|
|
7
|
+
home?: string;
|
|
8
|
+
env?: Record<string, string | undefined>;
|
|
9
|
+
}
|
|
10
|
+
export declare function dataDir(options: PathsResolverOptions): string;
|
|
11
|
+
/** The resolver (XDG / macOS) CACHE root for an app; `HASNA_CACHE_HOME` overrides it. */
|
|
12
|
+
export declare function cacheDir(options: PathsResolverOptions): string;
|
|
2
13
|
import type { EconomyRequest, EconomySession, EconomyProject, CostCenter, CostCenterBreakdown, CostCenterKind, Budget, BudgetStatus, CostSummary, ZeroCostModelBreakdown, ModelBreakdown, ProjectBreakdown, AgentBreakdown, AccountBreakdown, Period, Agent, SessionFilter } from '../types/index.js';
|
|
3
14
|
export declare function getMachineId(): string;
|
|
15
|
+
/**
|
|
16
|
+
* Resolve the user's home directory: $HOME, then $USERPROFILE (Windows), then
|
|
17
|
+
* the OS user database. A home that cannot be resolved is a hard error — never
|
|
18
|
+
* a literal "~" path (relative to cwd) and never an "undefined"-prefixed path.
|
|
19
|
+
*/
|
|
20
|
+
export declare function getHomeDir(): string;
|
|
21
|
+
/**
|
|
22
|
+
* The @hasna/paths-resolved (XDG / macOS home layout) data root for economy.
|
|
23
|
+
* This is the forward-looking home the XDG migration (hotfixes plan
|
|
24
|
+
* `0f49f56a`, task P3.3) moves the store toward: `~/.local/share/hasna/economy`
|
|
25
|
+
* on Linux, `~/Library/Application Support/Hasna/economy` on macOS. The home
|
|
26
|
+
* override mirrors the pre-existing $HOME-first resolution so the resolver
|
|
27
|
+
* follows the same home the legacy path does.
|
|
28
|
+
*/
|
|
29
|
+
export declare function getResolverDataRoot(): string;
|
|
30
|
+
/** The legacy (pre-XDG) data root: ~/.hasna/economy */
|
|
31
|
+
export declare function getLegacyDataRoot(): string;
|
|
32
|
+
/**
|
|
33
|
+
* Whether the resolver (XDG) data root should be adopted as the effective data
|
|
34
|
+
* root. The resolver root is adopted only when the operator has set
|
|
35
|
+
* `HASNA_DATA_HOME` (the data-kind override — a deliberate opt-in to the XDG
|
|
36
|
+
* layout) or the store has already been physically migrated there
|
|
37
|
+
* (`economy.db` exists). A machine that only redirects another kind (e.g.
|
|
38
|
+
* cache to tmpfs) must NOT have its data home moved, and a live store at the
|
|
39
|
+
* legacy home must never become invisible on upgrade.
|
|
40
|
+
*/
|
|
41
|
+
export declare function adoptResolverDataRoot(resolved: string, env?: Record<string, string | undefined>): boolean;
|
|
42
|
+
/** The exact-app override root, when set: `HASNA_ECONOMY_HOME`, then `ECONOMY_HOME`. */
|
|
43
|
+
export declare function getExactDataRoot(): string | undefined;
|
|
44
|
+
/**
|
|
45
|
+
* The effective data root for economy: an exact-app override
|
|
46
|
+
* (`HASNA_ECONOMY_HOME`, then `ECONOMY_HOME`) wins unconditionally; otherwise
|
|
47
|
+
* the resolver (XDG) data root once adopted; otherwise the legacy
|
|
48
|
+
* `~/.hasna/economy` default — an existing store never becomes invisible on
|
|
49
|
+
* upgrade. The store path (`HASNA_ECONOMY_DB_PATH` / `ECONOMY_DB`) is layered
|
|
50
|
+
* on top of this by `getDbPath`, so an explicit store path always wins
|
|
51
|
+
* regardless. The legacy `~/.economy` files are auto-migrated into the
|
|
52
|
+
* effective root, preserving the historical behavior.
|
|
53
|
+
*/
|
|
4
54
|
export declare function getDataDir(): string;
|
|
5
55
|
export declare function getDbPath(): string;
|
|
6
56
|
export declare function openDatabase(dbPath?: string, skipSeed?: boolean): Database;
|
|
@@ -65,6 +115,14 @@ export declare function deleteGoal(db: Database, id: string): void;
|
|
|
65
115
|
export declare function listGoals(db: Database): Goal[];
|
|
66
116
|
export declare function getGoalStatuses(db: Database): GoalStatus[];
|
|
67
117
|
export declare function getIngestState(db: Database, source: string, key: string): string | null;
|
|
118
|
+
/**
|
|
119
|
+
* Load every ingest_state row for one source into a Map. Ingest loops that
|
|
120
|
+
* check one key per corpus file (e.g. tens of thousands of session jsonl
|
|
121
|
+
* files) must use this instead of calling getIngestState per file — one
|
|
122
|
+
* prepared query per file turns an O(n) scan into an O(n) query blowup that
|
|
123
|
+
* dominates the whole ingest pass.
|
|
124
|
+
*/
|
|
125
|
+
export declare function loadIngestState(db: Database, source: string): Map<string, string>;
|
|
68
126
|
export declare function setIngestState(db: Database, source: string, key: string, value: string): void;
|
|
69
127
|
export declare function queryRequestsSince(db: Database, since: string): EconomyRequest[];
|
|
70
128
|
export interface FeedbackRecord {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"database.d.ts","sourceRoot":"","sources":["../../src/db/database.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,IAAI,QAAQ,EAAE,MAAM,qBAAqB,CAAA;
|
|
1
|
+
{"version":3,"file":"database.d.ts","sourceRoot":"","sources":["../../src/db/database.ts"],"names":[],"mappings":"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"}
|
package/dist/index.js
CHANGED
|
@@ -593,7 +593,60 @@ import { execFileSync } from "child_process";
|
|
|
593
593
|
import { copyFileSync, existsSync, mkdirSync, readdirSync, statSync } from "fs";
|
|
594
594
|
import { hostname, platform } from "os";
|
|
595
595
|
import { homedir } from "os";
|
|
596
|
-
import { join } from "path";
|
|
596
|
+
import { join, resolve } from "path";
|
|
597
|
+
import { homedir as pathsResolverHomedir } from "os";
|
|
598
|
+
import { join as pathsResolverJoin } from "path";
|
|
599
|
+
function pathsResolverAssertApp(app) {
|
|
600
|
+
if (typeof app !== "string" || app.length === 0) {
|
|
601
|
+
throw new TypeError("paths: app must be a non-empty string");
|
|
602
|
+
}
|
|
603
|
+
if (!PATHS_RESOLVER_APP_SLUG_RE.test(app)) {
|
|
604
|
+
throw new TypeError(`paths: invalid app slug "${app}" \u2014 expected lowercase kebab-case ([a-z0-9]+(-[a-z0-9]+)*)`);
|
|
605
|
+
}
|
|
606
|
+
}
|
|
607
|
+
function pathsResolverAssertKind(kind) {
|
|
608
|
+
if (!Object.keys(PATHS_RESOLVER_KIND_ENV).includes(kind)) {
|
|
609
|
+
throw new TypeError(`paths: invalid path kind "${kind}" \u2014 expected one of ${Object.keys(PATHS_RESOLVER_KIND_ENV).join(", ")}`);
|
|
610
|
+
}
|
|
611
|
+
}
|
|
612
|
+
function pathsResolverBaseDir(kind, options) {
|
|
613
|
+
pathsResolverAssertKind(kind);
|
|
614
|
+
const env = options.env ?? process.env;
|
|
615
|
+
const override = env[PATHS_RESOLVER_KIND_ENV[kind]];
|
|
616
|
+
if (typeof override === "string" && override.length > 0)
|
|
617
|
+
return override;
|
|
618
|
+
const home = options.home ?? pathsResolverHomedir();
|
|
619
|
+
const platform2 = options.platform ?? process.platform;
|
|
620
|
+
if (platform2 === "darwin") {
|
|
621
|
+
switch (kind) {
|
|
622
|
+
case "config":
|
|
623
|
+
case "data":
|
|
624
|
+
return pathsResolverJoin(home, "Library", "Application Support", "Hasna");
|
|
625
|
+
case "cache":
|
|
626
|
+
return pathsResolverJoin(home, "Library", "Caches", "Hasna");
|
|
627
|
+
case "state":
|
|
628
|
+
return pathsResolverJoin(home, "Library", "Logs", "Hasna");
|
|
629
|
+
}
|
|
630
|
+
}
|
|
631
|
+
switch (kind) {
|
|
632
|
+
case "config":
|
|
633
|
+
return pathsResolverJoin(home, ".config", "hasna");
|
|
634
|
+
case "data":
|
|
635
|
+
return pathsResolverJoin(home, ".local", "share", "hasna");
|
|
636
|
+
case "state":
|
|
637
|
+
return pathsResolverJoin(home, ".local", "state", "hasna");
|
|
638
|
+
case "cache":
|
|
639
|
+
return pathsResolverJoin(home, ".cache", "hasna");
|
|
640
|
+
}
|
|
641
|
+
}
|
|
642
|
+
function pathsResolverResolve(kind, options) {
|
|
643
|
+
pathsResolverAssertApp(options.app);
|
|
644
|
+
const appSegment = options.internal === true ? pathsResolverJoin("internal", options.app) : options.app;
|
|
645
|
+
return pathsResolverJoin(pathsResolverBaseDir(kind, options), appSegment);
|
|
646
|
+
}
|
|
647
|
+
function dataDir(options) {
|
|
648
|
+
return pathsResolverResolve("data", options);
|
|
649
|
+
}
|
|
597
650
|
function normalizeMachineId(value) {
|
|
598
651
|
const id = value?.trim().toLowerCase().split(".")[0];
|
|
599
652
|
return id && id.length > 0 ? id : null;
|
|
@@ -616,7 +669,7 @@ function macHostMachineId() {
|
|
|
616
669
|
return null;
|
|
617
670
|
}
|
|
618
671
|
function getMachineId() {
|
|
619
|
-
const envMachine = normalizeMachineId(process.env["
|
|
672
|
+
const envMachine = normalizeMachineId(process.env["HASNA_ECONOMY_MACHINE_ID"]);
|
|
620
673
|
if (envMachine)
|
|
621
674
|
return envMachine;
|
|
622
675
|
const hostMachine = normalizeMachineId(hostname()) ?? "unknown";
|
|
@@ -624,21 +677,48 @@ function getMachineId() {
|
|
|
624
677
|
return macHostMachineId() ?? hostMachine;
|
|
625
678
|
return hostMachine;
|
|
626
679
|
}
|
|
627
|
-
function
|
|
680
|
+
function getHomeDir() {
|
|
628
681
|
const home = process.env["HOME"] || process.env["USERPROFILE"] || homedir();
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
682
|
+
if (!home)
|
|
683
|
+
throw new Error("Could not resolve the user home directory");
|
|
684
|
+
return home;
|
|
685
|
+
}
|
|
686
|
+
function getResolverDataRoot() {
|
|
687
|
+
return dataDir({
|
|
688
|
+
app: "economy",
|
|
689
|
+
home: process.env["HOME"] || process.env["USERPROFILE"] || undefined
|
|
690
|
+
});
|
|
691
|
+
}
|
|
692
|
+
function getLegacyDataRoot() {
|
|
693
|
+
return join(getHomeDir(), ".hasna", "economy");
|
|
694
|
+
}
|
|
695
|
+
function adoptResolverDataRoot(resolved, env = process.env) {
|
|
696
|
+
const dataOverride = env.HASNA_DATA_HOME;
|
|
697
|
+
if (typeof dataOverride === "string" && dataOverride.trim().length > 0)
|
|
698
|
+
return true;
|
|
699
|
+
return existsSync(join(resolved, "economy.db"));
|
|
700
|
+
}
|
|
701
|
+
function getExactDataRoot() {
|
|
702
|
+
const dir = process.env["HASNA_ECONOMY_HOME"] ?? process.env["ECONOMY_HOME"];
|
|
703
|
+
if (dir && dir.trim())
|
|
704
|
+
return dir.trim();
|
|
705
|
+
return;
|
|
706
|
+
}
|
|
707
|
+
function getDataDir() {
|
|
708
|
+
const exact = getExactDataRoot();
|
|
709
|
+
const effective = exact ? resolve(exact) : adoptResolverDataRoot(getResolverDataRoot()) ? resolve(getResolverDataRoot()) : getLegacyDataRoot();
|
|
710
|
+
const oldDir = join(getHomeDir(), ".economy");
|
|
711
|
+
if (existsSync(oldDir) && !existsSync(effective)) {
|
|
712
|
+
mkdirSync(effective, { recursive: true });
|
|
633
713
|
for (const file of readdirSync(oldDir)) {
|
|
634
714
|
const oldPath = join(oldDir, file);
|
|
635
715
|
if (statSync(oldPath).isFile()) {
|
|
636
|
-
copyFileSync(oldPath, join(
|
|
716
|
+
copyFileSync(oldPath, join(effective, file));
|
|
637
717
|
}
|
|
638
718
|
}
|
|
639
719
|
}
|
|
640
|
-
mkdirSync(
|
|
641
|
-
return
|
|
720
|
+
mkdirSync(effective, { recursive: true });
|
|
721
|
+
return effective;
|
|
642
722
|
}
|
|
643
723
|
function getDbPath() {
|
|
644
724
|
if (process.env["HASNA_ECONOMY_DB_PATH"])
|
|
@@ -1962,8 +2042,16 @@ function queryUsageSnapshots(db, opts = {}) {
|
|
|
1962
2042
|
function listMachineRegistry(db) {
|
|
1963
2043
|
return db.prepare(`SELECT * FROM machines ORDER BY last_seen_at DESC`).all();
|
|
1964
2044
|
}
|
|
2045
|
+
var PATHS_RESOLVER_KIND_ENV, PATHS_RESOLVER_APP_SLUG_RE;
|
|
1965
2046
|
var init_database = __esm(() => {
|
|
1966
2047
|
init_sqlite_adapter();
|
|
2048
|
+
PATHS_RESOLVER_KIND_ENV = {
|
|
2049
|
+
config: "HASNA_CONFIG_HOME",
|
|
2050
|
+
data: "HASNA_DATA_HOME",
|
|
2051
|
+
state: "HASNA_STATE_HOME",
|
|
2052
|
+
cache: "HASNA_CACHE_HOME"
|
|
2053
|
+
};
|
|
2054
|
+
PATHS_RESOLVER_APP_SLUG_RE = /^[a-z0-9]+(?:-[a-z0-9]+)*$/;
|
|
1967
2055
|
});
|
|
1968
2056
|
|
|
1969
2057
|
// src/lib/agents.ts
|
|
@@ -1993,8 +2081,8 @@ import { randomUUID } from "crypto";
|
|
|
1993
2081
|
// package.json
|
|
1994
2082
|
var package_default = {
|
|
1995
2083
|
name: "@hasna/economy",
|
|
1996
|
-
version: "0.
|
|
1997
|
-
description: "AI coding cost tracker \u2014 CLI + MCP server + REST API
|
|
2084
|
+
version: "0.4.0",
|
|
2085
|
+
description: "AI coding cost tracker \u2014 CLI + MCP server + REST API for Claude Code, Codex, OpenCode, Cursor, Pi, and Hermes, with legacy Gemini CLI session and Gemini API billing ingestion",
|
|
1998
2086
|
repository: {
|
|
1999
2087
|
type: "git",
|
|
2000
2088
|
url: "git+https://github.com/hasna/economy.git"
|
|
@@ -2025,7 +2113,7 @@ var package_default = {
|
|
|
2025
2113
|
files: [
|
|
2026
2114
|
"dist",
|
|
2027
2115
|
"docs",
|
|
2028
|
-
"
|
|
2116
|
+
"postinstall.js",
|
|
2029
2117
|
"LICENSE",
|
|
2030
2118
|
"README.md",
|
|
2031
2119
|
"CHANGELOG.md",
|
|
@@ -2034,12 +2122,11 @@ var package_default = {
|
|
|
2034
2122
|
"CODE_OF_CONDUCT.md"
|
|
2035
2123
|
],
|
|
2036
2124
|
scripts: {
|
|
2037
|
-
build: "
|
|
2125
|
+
build: "bun build src/cli/index.ts --outdir dist/cli --target bun --packages external && bun build src/mcp/index.ts --outdir dist/mcp --target bun --packages external && bun build src/server/index.ts --outdir dist/server --target bun --packages external && bun build src/db/pg-sync-worker.ts --outdir dist/server --target bun --packages external && bun build src/otel/index.ts --outdir dist/otel --target bun --packages external && bun build src/index.ts --outdir dist --target bun --packages external && tsc --emitDeclarationOnly --outDir dist",
|
|
2038
2126
|
"build:cli": "bun build src/cli/index.ts --outdir dist/cli --target bun --packages external",
|
|
2039
2127
|
"build:mcp": "bun build src/mcp/index.ts --outdir dist/mcp --target bun --packages external",
|
|
2040
2128
|
"build:server": "bun build src/server/index.ts --outdir dist/server --target bun --packages external",
|
|
2041
2129
|
"build:lib": "bun build src/index.ts --outdir dist --target bun --packages external",
|
|
2042
|
-
"build:dashboard": "cd dashboard && bun run build",
|
|
2043
2130
|
"artifact-scan": "bun scripts/contracts-cli.mjs artifact-scan dist",
|
|
2044
2131
|
prepack: "bun run build && bun run artifact-scan",
|
|
2045
2132
|
typecheck: "tsc --noEmit",
|
|
@@ -2048,7 +2135,7 @@ var package_default = {
|
|
|
2048
2135
|
"dev:mcp": "bun run src/mcp/index.ts",
|
|
2049
2136
|
"dev:serve": "bun run src/server/index.ts",
|
|
2050
2137
|
"dev:otel": "bun run src/otel/index.ts",
|
|
2051
|
-
postinstall: "
|
|
2138
|
+
postinstall: "node postinstall.js"
|
|
2052
2139
|
},
|
|
2053
2140
|
keywords: [
|
|
2054
2141
|
"economy",
|
|
@@ -2069,11 +2156,8 @@ var package_default = {
|
|
|
2069
2156
|
access: "public"
|
|
2070
2157
|
},
|
|
2071
2158
|
dependencies: {
|
|
2072
|
-
"@hasna/
|
|
2073
|
-
"@hasna/agent-registry": "^0.1.0",
|
|
2074
|
-
"@hasna/contracts": "0.13.4",
|
|
2159
|
+
"@hasna/contracts": "1.0.2",
|
|
2075
2160
|
"@hasna/events": "^0.1.16",
|
|
2076
|
-
"@hasna/mcp-harness": "^0.1.0",
|
|
2077
2161
|
"@hasna/projects": "1.0.0",
|
|
2078
2162
|
"@modelcontextprotocol/sdk": "^1.12.1",
|
|
2079
2163
|
chalk: "^5.4.1",
|
|
@@ -2082,7 +2166,7 @@ var package_default = {
|
|
|
2082
2166
|
zod: "^3.24.2"
|
|
2083
2167
|
},
|
|
2084
2168
|
devDependencies: {
|
|
2085
|
-
"@types/bun": "
|
|
2169
|
+
"@types/bun": "1.3.14",
|
|
2086
2170
|
"@types/pg": "^8.20.0",
|
|
2087
2171
|
"bun-types": "latest",
|
|
2088
2172
|
typescript: "^5.7.2"
|
|
@@ -3069,19 +3153,144 @@ function queryModelEfficiency(db) {
|
|
|
3069
3153
|
FROM requests GROUP BY model ORDER BY cost DESC`).all();
|
|
3070
3154
|
}
|
|
3071
3155
|
|
|
3072
|
-
// src/lib/contracts-client/storage.ts
|
|
3073
|
-
import { resolveStorageClient } from "@hasna/contracts/client/storage";
|
|
3074
|
-
|
|
3075
3156
|
// src/lib/cloud-storage.ts
|
|
3157
|
+
import {
|
|
3158
|
+
appConfigDiskValue,
|
|
3159
|
+
ClientTransportConfigurationError,
|
|
3160
|
+
clientTransportEnvKeys,
|
|
3161
|
+
createClientTransport,
|
|
3162
|
+
credentialDiskSources,
|
|
3163
|
+
credentialOverrideEnvKey,
|
|
3164
|
+
credentialPointerEnvKey,
|
|
3165
|
+
CREDENTIAL_PROFILE_ENV_KEY,
|
|
3166
|
+
keychainConfigValue
|
|
3167
|
+
} from "@hasna/contracts/client";
|
|
3168
|
+
import { createHasnaStorageClient } from "@hasna/contracts/client/storage";
|
|
3076
3169
|
var ECONOMY_APP = "economy";
|
|
3170
|
+
var RETIRED_STORAGE_MODE_KEYS = [
|
|
3171
|
+
"HASNA_ECONOMY_STORAGE_MODE",
|
|
3172
|
+
"HASNA_ECONOMY_MODE",
|
|
3173
|
+
"ECONOMY_STORAGE_MODE",
|
|
3174
|
+
"ECONOMY_MODE"
|
|
3175
|
+
];
|
|
3176
|
+
function assertNoRetiredStorageMode(env) {
|
|
3177
|
+
const legacyKey = RETIRED_STORAGE_MODE_KEYS.find((key) => Object.hasOwn(env, key) && env[key] !== undefined);
|
|
3178
|
+
if (!legacyKey)
|
|
3179
|
+
return;
|
|
3180
|
+
throw new Error(`${legacyKey} was removed. Deployment modes no longer exist: delete the storage-mode variable. ` + `The client routes through the HTTP API resolved by @hasna/contracts ` + `(HASNA_ECONOMY_API_URL + HASNA_ECONOMY_API_KEY, the Keychain, or ` + `~/.hasna/economy/config/credentials), or serves the local SQLite store only when ` + `HASNA_ECONOMY_LOCAL=1 is set.`);
|
|
3181
|
+
}
|
|
3182
|
+
var LOCAL_STORAGE_OPT_IN_KEYS = ["HASNA_ECONOMY_LOCAL", "ECONOMY_LOCAL"];
|
|
3183
|
+
function envFlagSet(env, key) {
|
|
3184
|
+
const raw = env[key];
|
|
3185
|
+
if (raw === undefined)
|
|
3186
|
+
return false;
|
|
3187
|
+
const value = raw.trim().toLowerCase();
|
|
3188
|
+
return value !== "" && value !== "0" && value !== "false" && value !== "no" && value !== "off";
|
|
3189
|
+
}
|
|
3190
|
+
function localStorageExplicitlyOptedIn(env) {
|
|
3191
|
+
return LOCAL_STORAGE_OPT_IN_KEYS.some((key) => envFlagSet(env, key));
|
|
3192
|
+
}
|
|
3193
|
+
function economyAuthorityEnvKeys() {
|
|
3194
|
+
const keys = clientTransportEnvKeys(ECONOMY_APP);
|
|
3195
|
+
return [
|
|
3196
|
+
...keys.apiUrlKeys,
|
|
3197
|
+
...keys.apiKeyKeys,
|
|
3198
|
+
credentialOverrideEnvKey(ECONOMY_APP),
|
|
3199
|
+
credentialPointerEnvKey(ECONOMY_APP),
|
|
3200
|
+
CREDENTIAL_PROFILE_ENV_KEY
|
|
3201
|
+
];
|
|
3202
|
+
}
|
|
3203
|
+
function hasEconomyEnvAuthorityIntent(env) {
|
|
3204
|
+
return economyAuthorityEnvKeys().some((key) => (env[key] ?? "").trim().length > 0);
|
|
3205
|
+
}
|
|
3206
|
+
function hostedAuthorityConfigured(env, options = {}) {
|
|
3207
|
+
const keys = clientTransportEnvKeys(ECONOMY_APP);
|
|
3208
|
+
if (keys.apiUrlKeys.some((key) => (env[key] ?? "").trim().length > 0))
|
|
3209
|
+
return true;
|
|
3210
|
+
if (keychainConfigValue(ECONOMY_APP, env, options.credentials?.keychain) !== null)
|
|
3211
|
+
return true;
|
|
3212
|
+
return appConfigDiskValue(ECONOMY_APP, env, keys.apiUrlKeys) !== null;
|
|
3213
|
+
}
|
|
3214
|
+
function economyResolverEnv(env) {
|
|
3215
|
+
const blanks = economyAuthorityEnvKeys().filter((key) => (key in env) && (env[key] ?? "").trim() === "");
|
|
3216
|
+
if (blanks.length === 0)
|
|
3217
|
+
return env;
|
|
3218
|
+
const next = { ...env };
|
|
3219
|
+
for (const key of blanks)
|
|
3220
|
+
delete next[key];
|
|
3221
|
+
return next;
|
|
3222
|
+
}
|
|
3223
|
+
var CONTRACTS_AMBIENT_ENVIRONMENT = Symbol.for("hasna:contracts:ambientClientEnvironment");
|
|
3224
|
+
function isAmbientEconomyEnv(env) {
|
|
3225
|
+
if (typeof process !== "undefined" && env === process.env)
|
|
3226
|
+
return true;
|
|
3227
|
+
return env[CONTRACTS_AMBIENT_ENVIRONMENT] === true;
|
|
3228
|
+
}
|
|
3229
|
+
function economyResolverInputs(env, credentials = {}) {
|
|
3230
|
+
const normalised = economyResolverEnv(env);
|
|
3231
|
+
if (normalised === env)
|
|
3232
|
+
return { env: normalised, credentials };
|
|
3233
|
+
const keychain = { ...credentials.keychain };
|
|
3234
|
+
if (keychain.enabled === undefined && keychain.run === undefined) {
|
|
3235
|
+
keychain.enabled = isAmbientEconomyEnv(env);
|
|
3236
|
+
}
|
|
3237
|
+
return { env: normalised, credentials: { ...credentials, keychain } };
|
|
3238
|
+
}
|
|
3239
|
+
function resolveEconomyStorageClient(name, env, overrides = {}) {
|
|
3240
|
+
const { env: resolverEnv, credentials } = economyResolverInputs(env, overrides.credentials);
|
|
3241
|
+
const wired = createClientTransport(name, resolverEnv, {
|
|
3242
|
+
credentials,
|
|
3243
|
+
...overrides.fetchImpl ? { fetchImpl: overrides.fetchImpl } : {},
|
|
3244
|
+
...overrides.headers ? { headers: overrides.headers } : {},
|
|
3245
|
+
...overrides.timeoutMs ? { timeoutMs: overrides.timeoutMs } : {},
|
|
3246
|
+
...overrides.retry !== undefined ? { retry: overrides.retry } : {},
|
|
3247
|
+
...overrides.sleepImpl ? { sleepImpl: overrides.sleepImpl } : {}
|
|
3248
|
+
});
|
|
3249
|
+
return {
|
|
3250
|
+
transport: "http",
|
|
3251
|
+
client: createHasnaStorageClient(name, wired.client),
|
|
3252
|
+
resolution: wired.resolution
|
|
3253
|
+
};
|
|
3254
|
+
}
|
|
3255
|
+
function localEconomyNotice() {
|
|
3256
|
+
return `economy: local mode (${LOCAL_STORAGE_OPT_IN_KEYS[0]}=1) \u2014 reading and writing the on-box ` + `SQLite store, not the hosted fleet. Data in the shared economy API is NOT included.`;
|
|
3257
|
+
}
|
|
3258
|
+
function credentialRequiredError(env, cause) {
|
|
3259
|
+
const keys = clientTransportEnvKeys(ECONOMY_APP);
|
|
3260
|
+
const clientEnv = env;
|
|
3261
|
+
const detail = cause instanceof Error ? cause.message : `No API key could be resolved for '${ECONOMY_APP}'. Looked in the Keychain (macOS only), ` + `then for a credential file at ${credentialDiskSources(ECONOMY_APP, clientEnv).join(" or ") || "<no HOME set>"}, ` + `then for ${keys.apiKeyKeys[0]} in the environment.`;
|
|
3262
|
+
const wayOut = hostedAuthorityConfigured(clientEnv) ? `${keys.apiUrlKeys[0]} (or the Keychain hasna.credentials.${ECONOMY_APP}.api-url item, or ` + `~/.hasna/${ECONOMY_APP}/config/credentials) selects a hosted service, so ${LOCAL_STORAGE_OPT_IN_KEYS[0]} ` + `does not apply; unset the authority to use the local store.` : `Or set ${LOCAL_STORAGE_OPT_IN_KEYS[0]}=1 to explicitly opt into the local store.`;
|
|
3263
|
+
return new Error(`Economy fails closed instead of silently serving the local SQLite store: ${detail} ` + `Set ${keys.apiUrlKeys[0]} and ${keys.apiKeyKeys[0]} (or store the key in the Keychain item ` + `hasna.credentials.${ECONOMY_APP}.api-key, or in ~/.hasna/${ECONOMY_APP}/config/credentials) to use the ` + `hosted economy API at ${keys.apiUrlKeys[0]} or the default fleet gateway. ` + wayOut);
|
|
3264
|
+
}
|
|
3077
3265
|
var cache;
|
|
3266
|
+
var localNoticePrinted = false;
|
|
3078
3267
|
function resolveEconomyCloudStorage(env = process.env, overrides) {
|
|
3079
|
-
|
|
3080
|
-
|
|
3268
|
+
assertNoRetiredStorageMode(env);
|
|
3269
|
+
const clientEnv = env;
|
|
3270
|
+
if (localStorageExplicitlyOptedIn(env) && !hasEconomyEnvAuthorityIntent(clientEnv)) {
|
|
3271
|
+
return { active: false, client: null };
|
|
3272
|
+
}
|
|
3273
|
+
let resolved;
|
|
3274
|
+
try {
|
|
3275
|
+
resolved = resolveEconomyStorageClient(ECONOMY_APP, clientEnv, overrides ?? {});
|
|
3276
|
+
} catch (error) {
|
|
3277
|
+
if (error instanceof ClientTransportConfigurationError) {
|
|
3278
|
+
throw credentialRequiredError(env, error);
|
|
3279
|
+
}
|
|
3280
|
+
throw error;
|
|
3281
|
+
}
|
|
3282
|
+
return { active: true, client: resolved.client };
|
|
3081
3283
|
}
|
|
3082
3284
|
function economyCloudStorage(env = process.env) {
|
|
3083
|
-
if (cache === undefined)
|
|
3285
|
+
if (cache === undefined) {
|
|
3084
3286
|
cache = resolveEconomyCloudStorage(env);
|
|
3287
|
+
if (!cache.active && !localNoticePrinted) {
|
|
3288
|
+
localNoticePrinted = true;
|
|
3289
|
+
if (typeof process !== "undefined")
|
|
3290
|
+
process.stderr.write(`${localEconomyNotice()}
|
|
3291
|
+
`);
|
|
3292
|
+
}
|
|
3293
|
+
}
|
|
3085
3294
|
return cache;
|
|
3086
3295
|
}
|
|
3087
3296
|
function cleanQuery(query) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"claude.d.ts","sourceRoot":"","sources":["../../src/ingest/claude.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,aAAa,IAAI,QAAQ,EAAE,MAAM,yBAAyB,CAAA;AAYxE,OAAO,KAAK,EAAkB,KAAK,EAAE,MAAM,mBAAmB,CAAA;
|
|
1
|
+
{"version":3,"file":"claude.d.ts","sourceRoot":"","sources":["../../src/ingest/claude.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,aAAa,IAAI,QAAQ,EAAE,MAAM,yBAAyB,CAAA;AAYxE,OAAO,KAAK,EAAkB,KAAK,EAAE,MAAM,mBAAmB,CAAA;AAiE9D,wBAAsB,YAAY,CAChC,EAAE,EAAE,QAAQ,EACZ,OAAO,UAAQ,EACf,WAAW,SAAsB,GAChC,OAAO,CAAC;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,CAAC,CAEhE;AAED,wBAAsB,YAAY,CAChC,EAAE,EAAE,QAAQ,EACZ,OAAO,UAAQ,EACf,WAAW,SAAsB,GAChC,OAAO,CAAC;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,CAAC,CAEhE;AAED,wBAAsB,mBAAmB,CACvC,EAAE,EAAE,QAAQ,EACZ,WAAW,EAAE,MAAM,EACnB,SAAS,EAAE,KAAK,EAChB,OAAO,UAAQ,GACd,OAAO,CAAC;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,CAAC,CA8IhE"}
|
package/dist/ingest/loops.d.ts
CHANGED
|
@@ -1,4 +1,23 @@
|
|
|
1
|
+
export type PathKind = "config" | "data" | "state" | "cache";
|
|
2
|
+
export interface PathsResolverOptions {
|
|
3
|
+
app: string;
|
|
4
|
+
internal?: boolean;
|
|
5
|
+
platform?: string;
|
|
6
|
+
home?: string;
|
|
7
|
+
env?: Record<string, string | undefined>;
|
|
8
|
+
}
|
|
9
|
+
export declare function dataDir(options: PathsResolverOptions): string;
|
|
1
10
|
import type { SqliteAdapter as Database } from '../db/sqlite-adapter.js';
|
|
11
|
+
/**
|
|
12
|
+
* The default OpenLoops store path, resolved through the @hasna/paths resolver
|
|
13
|
+
* (XDG / macOS home layout): the resolver data root for `loops` once its store
|
|
14
|
+
* has been migrated there (`loops.db` present), otherwise the legacy
|
|
15
|
+
* `~/.hasna/loops/loops.db` — a legacy-read fallback, so economy keeps reading
|
|
16
|
+
* loops' store whichever side of the XDG migration loops is on. The exact-app
|
|
17
|
+
* override `HASNA_ECONOMY_LOOPS_DB_PATH` still wins unconditionally.
|
|
18
|
+
*/
|
|
19
|
+
export declare function defaultLoopsDbPath(): string;
|
|
20
|
+
export declare function loopsDbPath(): string;
|
|
2
21
|
export declare function ingestLoops(db: Database, verbose?: boolean): Promise<{
|
|
3
22
|
sessions: number;
|
|
4
23
|
requests: number;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"loops.d.ts","sourceRoot":"","sources":["../../src/ingest/loops.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"loops.d.ts","sourceRoot":"","sources":["../../src/ingest/loops.ts"],"names":[],"mappings":"AAYA,MAAM,MAAM,QAAQ,GAAG,QAAQ,GAAG,MAAM,GAAG,OAAO,GAAG,OAAO,CAAC;AAS7D,MAAM,WAAW,oBAAoB;IACnC,GAAG,EAAE,MAAM,CAAC;IACZ,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,GAAG,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAAC;CAC1C;AA0DD,wBAAgB,OAAO,CAAC,OAAO,EAAE,oBAAoB,GAAG,MAAM,CAE7D;AACD,OAAO,KAAK,EAAE,aAAa,IAAI,QAAQ,EAAE,MAAM,yBAAyB,CAAA;AAiCxE;;;;;;;GAOG;AACH,wBAAgB,kBAAkB,IAAI,MAAM,CAc3C;AAED,wBAAgB,WAAW,IAAI,MAAM,CAEpC;AAwGD,wBAAsB,WAAW,CAAC,EAAE,EAAE,QAAQ,EAAE,OAAO,UAAQ,GAAG,OAAO,CAAC;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,CAAC,CA+FhH"}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { type CredentialChainOptions } from '@hasna/contracts/client';
|
|
3
|
+
/** Test injection for the accounts credential chain (keychain runner, tier-1 key). */
|
|
4
|
+
export interface ResolveAccountsStoreOptions {
|
|
5
|
+
credentials?: CredentialChainOptions;
|
|
6
|
+
}
|
|
7
|
+
/** Minimal profile record — the fields economy's attribution reads. */
|
|
8
|
+
declare const profileSchema: z.ZodObject<{
|
|
9
|
+
name: z.ZodString;
|
|
10
|
+
tool: z.ZodString;
|
|
11
|
+
email: z.ZodOptional<z.ZodString>;
|
|
12
|
+
displayName: z.ZodOptional<z.ZodString>;
|
|
13
|
+
dir: z.ZodString;
|
|
14
|
+
description: z.ZodOptional<z.ZodString>;
|
|
15
|
+
createdAt: z.ZodString;
|
|
16
|
+
lastUsedAt: z.ZodOptional<z.ZodString>;
|
|
17
|
+
}, "strip", z.ZodTypeAny, {
|
|
18
|
+
name: string;
|
|
19
|
+
tool: string;
|
|
20
|
+
dir: string;
|
|
21
|
+
createdAt: string;
|
|
22
|
+
description?: string | undefined;
|
|
23
|
+
email?: string | undefined;
|
|
24
|
+
displayName?: string | undefined;
|
|
25
|
+
lastUsedAt?: string | undefined;
|
|
26
|
+
}, {
|
|
27
|
+
name: string;
|
|
28
|
+
tool: string;
|
|
29
|
+
dir: string;
|
|
30
|
+
createdAt: string;
|
|
31
|
+
description?: string | undefined;
|
|
32
|
+
email?: string | undefined;
|
|
33
|
+
displayName?: string | undefined;
|
|
34
|
+
lastUsedAt?: string | undefined;
|
|
35
|
+
}>;
|
|
36
|
+
/** Minimal tool definition — economy reads `id` and `envVar` (dir matching). */
|
|
37
|
+
declare const toolDefSchema: z.ZodObject<{
|
|
38
|
+
id: z.ZodString;
|
|
39
|
+
label: z.ZodString;
|
|
40
|
+
envVar: z.ZodString;
|
|
41
|
+
defaultDir: z.ZodString;
|
|
42
|
+
bin: z.ZodString;
|
|
43
|
+
}, "strip", z.ZodTypeAny, {
|
|
44
|
+
label: string;
|
|
45
|
+
id: string;
|
|
46
|
+
envVar: string;
|
|
47
|
+
defaultDir: string;
|
|
48
|
+
bin: string;
|
|
49
|
+
}, {
|
|
50
|
+
label: string;
|
|
51
|
+
id: string;
|
|
52
|
+
envVar: string;
|
|
53
|
+
defaultDir: string;
|
|
54
|
+
bin: string;
|
|
55
|
+
}>;
|
|
56
|
+
export type Profile = z.infer<typeof profileSchema>;
|
|
57
|
+
export type ToolDef = z.infer<typeof toolDefSchema>;
|
|
58
|
+
/**
|
|
59
|
+
* The minimal store surface economy uses for attribution. Both transports
|
|
60
|
+
* (local JSON and accounts-serve API) implement it.
|
|
61
|
+
*/
|
|
62
|
+
export interface AccountsStore {
|
|
63
|
+
readonly transport: 'local' | 'api';
|
|
64
|
+
listProfiles(tool?: string): Promise<Profile[]>;
|
|
65
|
+
findProfile(name: string, tool?: string): Promise<Profile | undefined>;
|
|
66
|
+
currentProfile(tool: string): Promise<Profile | undefined>;
|
|
67
|
+
listTools(): Promise<ToolDef[]>;
|
|
68
|
+
}
|
|
69
|
+
/** The profile name last applied to a tool's live default paths, if any. */
|
|
70
|
+
export declare function appliedProfileName(toolId: string): string | undefined;
|
|
71
|
+
/**
|
|
72
|
+
* Resolve the active registry store for this process — the credential chain
|
|
73
|
+
* alone: the API transport when `@hasna/contracts` resolves an accounts
|
|
74
|
+
* credential for this environment (env `HASNA_ACCOUNTS_API_KEY` / legacy
|
|
75
|
+
* `ACCOUNTS_API_KEY`, the accounts credentials file, or the Keychain, with the
|
|
76
|
+
* authority defaulted to the fleet gateway `https://api.hasna.com/accounts`),
|
|
77
|
+
* else the local JSON registry. Retired `*_STORAGE_MODE` / `*_MODE` variables
|
|
78
|
+
* are a hard error so a half-migrated deployment fails loudly instead of
|
|
79
|
+
* silently reading the wrong dataset.
|
|
80
|
+
*/
|
|
81
|
+
export declare function resolveStore(env?: NodeJS.ProcessEnv, options?: ResolveAccountsStoreOptions): AccountsStore;
|
|
82
|
+
export {};
|
|
83
|
+
//# sourceMappingURL=accounts-store.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"accounts-store.d.ts","sourceRoot":"","sources":["../../src/lib/accounts-store.ts"],"names":[],"mappings":"AAkCA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AACvB,OAAO,EAA6C,KAAK,sBAAsB,EAAE,MAAM,yBAAyB,CAAA;AAKhH,sFAAsF;AACtF,MAAM,WAAW,2BAA2B;IAC1C,WAAW,CAAC,EAAE,sBAAsB,CAAA;CACrC;AAKD,uEAAuE;AACvE,QAAA,MAAM,aAAa;;;;;;;;;;;;;;;;;;;;;;;;;;;EASjB,CAAA;AAEF,gFAAgF;AAChF,QAAA,MAAM,aAAa;;;;;;;;;;;;;;;;;;EAMjB,CAAA;AAYF,MAAM,MAAM,OAAO,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,aAAa,CAAC,CAAA;AACnD,MAAM,MAAM,OAAO,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,aAAa,CAAC,CAAA;AAEnD;;;GAGG;AACH,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,SAAS,EAAE,OAAO,GAAG,KAAK,CAAA;IACnC,YAAY,CAAC,IAAI,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,EAAE,CAAC,CAAA;IAC/C,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,GAAG,SAAS,CAAC,CAAA;IACtE,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,GAAG,SAAS,CAAC,CAAA;IAC1D,SAAS,IAAI,OAAO,CAAC,OAAO,EAAE,CAAC,CAAA;CAChC;AAqDD,4EAA4E;AAC5E,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAErE;AA4PD;;;;;;;;;GASG;AACH,wBAAgB,YAAY,CAC1B,GAAG,GAAE,MAAM,CAAC,UAAwB,EACpC,OAAO,GAAE,2BAAgC,GACxC,aAAa,CAiBf"}
|