unbrowse 3.1.0 → 3.2.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/cli.js +455 -96
- package/dist/index.js +2 -6
- package/dist/mcp.js +695 -46
- package/dist/server.js +25811 -0
- package/package.json +1 -2
- package/vendor/kuri/darwin-arm64/kuri +0 -0
- package/vendor/kuri/darwin-x64/kuri +0 -0
- package/vendor/kuri/linux-arm64/kuri +0 -0
- package/vendor/kuri/linux-x64/kuri +0 -0
- package/vendor/kuri/manifest.json +7 -10
- package/runtime-src/agent-outcome.ts +0 -166
- package/runtime-src/analytics-session.ts +0 -55
- package/runtime-src/api/browse-index.ts +0 -317
- package/runtime-src/api/browse-session.ts +0 -572
- package/runtime-src/api/browse-submit-prereqs.ts +0 -48
- package/runtime-src/api/browse-submit.ts +0 -1184
- package/runtime-src/api/routes.ts +0 -1823
- package/runtime-src/auth/browser-cookies.ts +0 -423
- package/runtime-src/auth/index.ts +0 -535
- package/runtime-src/auth/runtime.ts +0 -116
- package/runtime-src/browser/index.ts +0 -659
- package/runtime-src/browser/types.ts +0 -41
- package/runtime-src/build-info.generated.ts +0 -6
- package/runtime-src/capture/index.ts +0 -1794
- package/runtime-src/capture/prefetch.ts +0 -95
- package/runtime-src/capture/rsc.ts +0 -45
- package/runtime-src/cli/shortcuts.ts +0 -273
- package/runtime-src/cli.ts +0 -1572
- package/runtime-src/client/graph-client.ts +0 -100
- package/runtime-src/client/index.ts +0 -1425
- package/runtime-src/debug-trace.ts +0 -18
- package/runtime-src/domain.ts +0 -38
- package/runtime-src/execution/index.ts +0 -3397
- package/runtime-src/execution/retry.ts +0 -46
- package/runtime-src/execution/robots.ts +0 -167
- package/runtime-src/execution/search-forms.ts +0 -188
- package/runtime-src/extraction/index.ts +0 -1507
- package/runtime-src/foundry/publish-bundle.ts +0 -392
- package/runtime-src/graph/agent-augment.ts +0 -315
- package/runtime-src/graph/index.ts +0 -1524
- package/runtime-src/graph/local-fixtures.ts +0 -393
- package/runtime-src/graph/local-harness.ts +0 -646
- package/runtime-src/graph/planner.ts +0 -411
- package/runtime-src/graph/session.ts +0 -294
- package/runtime-src/graph/trace-store.ts +0 -136
- package/runtime-src/index.ts +0 -24
- package/runtime-src/indexer/index.ts +0 -465
- package/runtime-src/intent-match.ts +0 -1515
- package/runtime-src/kuri/client.ts +0 -1839
- package/runtime-src/logger.ts +0 -30
- package/runtime-src/marketplace/index.ts +0 -103
- package/runtime-src/mcp.ts +0 -1747
- package/runtime-src/orchestrator/browser-agent.ts +0 -374
- package/runtime-src/orchestrator/dag-advisor.ts +0 -59
- package/runtime-src/orchestrator/dag-feedback.ts +0 -257
- package/runtime-src/orchestrator/first-pass-action.ts +0 -403
- package/runtime-src/orchestrator/index.ts +0 -4480
- package/runtime-src/orchestrator/passive-publish.ts +0 -187
- package/runtime-src/orchestrator/timing-economics.ts +0 -80
- package/runtime-src/payments/cascade.ts +0 -137
- package/runtime-src/payments/index.ts +0 -270
- package/runtime-src/payments/lobster-pay.ts +0 -182
- package/runtime-src/payments/wallet.ts +0 -98
- package/runtime-src/publish/review-context.ts +0 -93
- package/runtime-src/publish/sanitize.ts +0 -197
- package/runtime-src/publish/schema-review.ts +0 -192
- package/runtime-src/publish-admission.ts +0 -388
- package/runtime-src/ratelimit/index.ts +0 -23
- package/runtime-src/reverse-engineer/bundle-scanner.ts +0 -127
- package/runtime-src/reverse-engineer/description-prompt.ts +0 -213
- package/runtime-src/reverse-engineer/index.ts +0 -1551
- package/runtime-src/router.ts +0 -17
- package/runtime-src/routing-telemetry.ts +0 -395
- package/runtime-src/runtime/browser-access.ts +0 -11
- package/runtime-src/runtime/browser-auth.ts +0 -12
- package/runtime-src/runtime/browser-host.ts +0 -48
- package/runtime-src/runtime/lifecycle.ts +0 -17
- package/runtime-src/runtime/local-server.ts +0 -311
- package/runtime-src/runtime/paths.ts +0 -99
- package/runtime-src/runtime/setup.ts +0 -251
- package/runtime-src/runtime/supervisor.ts +0 -69
- package/runtime-src/runtime/update-hints.ts +0 -351
- package/runtime-src/server.ts +0 -100
- package/runtime-src/session-logs.ts +0 -142
- package/runtime-src/settings.ts +0 -221
- package/runtime-src/single-binary.ts +0 -143
- package/runtime-src/site-policy.ts +0 -54
- package/runtime-src/stale-cleanup-runner.ts +0 -144
- package/runtime-src/stale-cleanup.ts +0 -133
- package/runtime-src/telemetry-attribution.ts +0 -120
- package/runtime-src/telemetry.ts +0 -253
- package/runtime-src/template-params.ts +0 -141
- package/runtime-src/transform/drift.ts +0 -60
- package/runtime-src/transform/index.ts +0 -277
- package/runtime-src/types/index.ts +0 -1
- package/runtime-src/types/skill.ts +0 -912
- package/runtime-src/vault/index.ts +0 -196
- package/runtime-src/verification/auth-gate.ts +0 -8
- package/runtime-src/verification/candidates.ts +0 -27
- package/runtime-src/verification/index.ts +0 -120
- package/runtime-src/verification/matrix.ts +0 -30
- package/runtime-src/version.ts +0 -148
- package/runtime-src/workflow/artifact.ts +0 -161
- package/runtime-src/workflow/compile.ts +0 -808
- package/runtime-src/workflow/publish.ts +0 -225
- package/runtime-src/workflow/runtime.ts +0 -213
- package/vendor/kuri/win-x64/kuri.exe +0 -0
package/dist/cli.js
CHANGED
|
@@ -31,7 +31,7 @@ var __promiseAll = (args) => Promise.all(args);
|
|
|
31
31
|
var __require = /* @__PURE__ */ createRequire(import.meta.url);
|
|
32
32
|
|
|
33
33
|
// ../../src/build-info.generated.ts
|
|
34
|
-
var BUILD_RELEASE_VERSION = "3.
|
|
34
|
+
var BUILD_RELEASE_VERSION = "3.2.0", BUILD_GIT_SHA = "c3fc3f822751", BUILD_CODE_HASH = "1488fc1d92b7", BUILD_RELEASE_MANIFEST_BASE64 = "eyJzY2hlbWFfdmVyc2lvbiI6MSwicmVsZWFzZV92ZXJzaW9uIjoiMy4yLjAiLCJnaXRfc2hhIjoiYzNmYzNmODIyNzUxIiwiY29kZV9oYXNoIjoiMTQ4OGZjMWQ5MmI3IiwidHJhY2VfdmVyc2lvbiI6IjE0ODhmYzFkOTJiN0BjM2ZjM2Y4MjI3NTEiLCJpc3N1ZWRfYXQiOiIyMDI2LTA0LTA2VDA1OjA2OjAxLjIwMFoifQ", BUILD_RELEASE_MANIFEST_SIGNATURE = "xCBEHEB2UsniVYLfzuTpoXlcomZHL2pXht-7Ii1e7mM", BUILD_DEFAULT_BACKEND_URL = "https://beta-api.unbrowse.ai";
|
|
35
35
|
|
|
36
36
|
// ../../src/version.ts
|
|
37
37
|
import { createHash } from "crypto";
|
|
@@ -400,7 +400,7 @@ var LOBSTER_PAY_TIMEOUT_MS = 30000, cachedCommand = undefined;
|
|
|
400
400
|
var init_lobster_pay = () => {};
|
|
401
401
|
|
|
402
402
|
// ../../src/runtime/paths.ts
|
|
403
|
-
import { existsSync as
|
|
403
|
+
import { existsSync as existsSync6, mkdirSync as mkdirSync3, realpathSync } from "node:fs";
|
|
404
404
|
import os from "node:os";
|
|
405
405
|
import path from "node:path";
|
|
406
406
|
import { createRequire as createRequire2 } from "node:module";
|
|
@@ -414,7 +414,7 @@ function getPackageRoot(metaUrl) {
|
|
|
414
414
|
let dir = getModuleDir(metaUrl);
|
|
415
415
|
const root = path.parse(dir).root;
|
|
416
416
|
while (dir !== root) {
|
|
417
|
-
if (
|
|
417
|
+
if (existsSync6(path.join(dir, "package.json")))
|
|
418
418
|
return dir;
|
|
419
419
|
dir = path.dirname(dir);
|
|
420
420
|
}
|
|
@@ -433,7 +433,7 @@ function runtimeArgsForEntrypoint(metaUrl, entrypoint) {
|
|
|
433
433
|
const req = createRequire2(metaUrl);
|
|
434
434
|
const tsxPkg = req.resolve("tsx/package.json");
|
|
435
435
|
const tsxLoader = path.join(path.dirname(tsxPkg), "dist", "loader.mjs");
|
|
436
|
-
if (
|
|
436
|
+
if (existsSync6(tsxLoader))
|
|
437
437
|
return ["--import", pathToFileURL(tsxLoader).href, entrypoint];
|
|
438
438
|
} catch {}
|
|
439
439
|
return ["--import", "tsx", entrypoint];
|
|
@@ -441,16 +441,16 @@ function runtimeArgsForEntrypoint(metaUrl, entrypoint) {
|
|
|
441
441
|
function getUnbrowseHome() {
|
|
442
442
|
return path.join(os.homedir(), ".unbrowse");
|
|
443
443
|
}
|
|
444
|
-
function
|
|
445
|
-
if (!
|
|
446
|
-
|
|
444
|
+
function ensureDir2(dir) {
|
|
445
|
+
if (!existsSync6(dir))
|
|
446
|
+
mkdirSync3(dir, { recursive: true });
|
|
447
447
|
return dir;
|
|
448
448
|
}
|
|
449
449
|
function getLogsDir() {
|
|
450
|
-
return
|
|
450
|
+
return ensureDir2(path.join(getUnbrowseHome(), "logs"));
|
|
451
451
|
}
|
|
452
452
|
function getRunDir() {
|
|
453
|
-
return
|
|
453
|
+
return ensureDir2(process.env.UNBROWSE_RUN_DIR || path.join(getUnbrowseHome(), "run"));
|
|
454
454
|
}
|
|
455
455
|
function sanitizeSegment(value) {
|
|
456
456
|
return value.replace(/[^a-zA-Z0-9.-]+/g, "_");
|
|
@@ -586,7 +586,7 @@ var init_logger = __esm(() => {
|
|
|
586
586
|
|
|
587
587
|
// ../../src/kuri/client.ts
|
|
588
588
|
import { execFileSync as execFileSync2, spawn as spawn2 } from "node:child_process";
|
|
589
|
-
import { existsSync as
|
|
589
|
+
import { existsSync as existsSync9 } from "node:fs";
|
|
590
590
|
import path5 from "node:path";
|
|
591
591
|
function createBrokerState(port = KURI_DEFAULT_PORT) {
|
|
592
592
|
return {
|
|
@@ -661,7 +661,7 @@ function findKuriBinary() {
|
|
|
661
661
|
if (process.env.KURI_BIN)
|
|
662
662
|
return process.env.KURI_BIN;
|
|
663
663
|
const candidates = getKuriBinaryCandidates();
|
|
664
|
-
return candidates.find((candidate) =>
|
|
664
|
+
return candidates.find((candidate) => existsSync9(candidate)) ?? candidates[0] ?? kuriBinaryName();
|
|
665
665
|
}
|
|
666
666
|
var KURI_DEFAULT_PORT = 7700, defaultBrokerState, brokerClients;
|
|
667
667
|
var init_client2 = __esm(() => {
|
|
@@ -684,7 +684,7 @@ var init_browser_access = () => {};
|
|
|
684
684
|
|
|
685
685
|
// ../../src/capture/index.ts
|
|
686
686
|
import { nanoid as nanoid2 } from "nanoid";
|
|
687
|
-
var activeTabRegistry, interceptorInjectedTabs;
|
|
687
|
+
var activeTabRegistry, interceptorInjectedTabs, cdpDocStartTabs, cdpCapturedHeaders;
|
|
688
688
|
var init_capture = __esm(() => {
|
|
689
689
|
init_client2();
|
|
690
690
|
init_domain();
|
|
@@ -692,6 +692,8 @@ var init_capture = __esm(() => {
|
|
|
692
692
|
init_browser_access();
|
|
693
693
|
activeTabRegistry = new Set;
|
|
694
694
|
interceptorInjectedTabs = new Set;
|
|
695
|
+
cdpDocStartTabs = new Set;
|
|
696
|
+
cdpCapturedHeaders = new Map;
|
|
695
697
|
});
|
|
696
698
|
|
|
697
699
|
// ../../src/transform/index.ts
|
|
@@ -701,11 +703,11 @@ var init_transform = __esm(() => {
|
|
|
701
703
|
});
|
|
702
704
|
|
|
703
705
|
// ../../src/debug-trace.ts
|
|
704
|
-
import { join as
|
|
706
|
+
import { join as join6 } from "node:path";
|
|
705
707
|
import { nanoid as nanoid3 } from "nanoid";
|
|
706
708
|
var TRACE_DIR;
|
|
707
709
|
var init_debug_trace = __esm(() => {
|
|
708
|
-
TRACE_DIR = process.env.TRACES_DIR ??
|
|
710
|
+
TRACE_DIR = process.env.TRACES_DIR ?? join6(process.cwd(), "traces");
|
|
709
711
|
});
|
|
710
712
|
|
|
711
713
|
// ../../src/publish/sanitize.ts
|
|
@@ -794,9 +796,18 @@ var init_bundle_scanner = __esm(() => {
|
|
|
794
796
|
init_logger();
|
|
795
797
|
});
|
|
796
798
|
|
|
799
|
+
// ../../src/reverse-engineer/token-sources.ts
|
|
800
|
+
var init_token_sources = () => {};
|
|
801
|
+
|
|
802
|
+
// ../../src/execution/token-resolver.ts
|
|
803
|
+
var init_token_resolver = __esm(() => {
|
|
804
|
+
init_token_sources();
|
|
805
|
+
init_client2();
|
|
806
|
+
});
|
|
807
|
+
|
|
797
808
|
// ../../src/vault/index.ts
|
|
798
|
-
import { join as
|
|
799
|
-
import { homedir as
|
|
809
|
+
import { join as join7 } from "path";
|
|
810
|
+
import { homedir as homedir5 } from "os";
|
|
800
811
|
function normalizeKeytarModule(mod) {
|
|
801
812
|
let candidate = mod;
|
|
802
813
|
for (let depth = 0;depth < 3; depth++) {
|
|
@@ -818,9 +829,9 @@ var init_vault = __esm(async () => {
|
|
|
818
829
|
try {
|
|
819
830
|
keytar = normalizeKeytarModule(await import("keytar"));
|
|
820
831
|
} catch {}
|
|
821
|
-
VAULT_DIR =
|
|
822
|
-
VAULT_FILE =
|
|
823
|
-
KEY_FILE =
|
|
832
|
+
VAULT_DIR = join7(homedir5(), ".unbrowse", "vault");
|
|
833
|
+
VAULT_FILE = join7(VAULT_DIR, "credentials.enc");
|
|
834
|
+
KEY_FILE = join7(VAULT_DIR, ".key");
|
|
824
835
|
vaultLock = Promise.resolve();
|
|
825
836
|
});
|
|
826
837
|
|
|
@@ -897,18 +908,6 @@ var init_extraction = __esm(() => {
|
|
|
897
908
|
CHROME_TAGS = new Set(["nav", "footer", "header"]);
|
|
898
909
|
});
|
|
899
910
|
|
|
900
|
-
// ../../src/graph/agent-augment.ts
|
|
901
|
-
var DEFAULT_MODEL, ENABLED, AUGMENT_TIMEOUT_MS, MAX_AUGMENT_ENDPOINTS, MAX_AUGMENT_PAYLOAD_CHARS, GENERIC_SEMANTIC_TYPES;
|
|
902
|
-
var init_agent_augment = __esm(() => {
|
|
903
|
-
init_graph();
|
|
904
|
-
DEFAULT_MODEL = process.env.UNBROWSE_AGENT_SEMANTIC_MODEL ?? process.env.UNBROWSE_AGENT_JUDGE_MODEL ?? "gpt-4.1-mini";
|
|
905
|
-
ENABLED = process.env.UNBROWSE_AGENT_SEMANTIC_AUGMENT !== "0";
|
|
906
|
-
AUGMENT_TIMEOUT_MS = Number(process.env.UNBROWSE_AGENT_SEMANTIC_TIMEOUT_MS ?? 8000);
|
|
907
|
-
MAX_AUGMENT_ENDPOINTS = Math.max(1, Number(process.env.UNBROWSE_AGENT_SEMANTIC_MAX_ENDPOINTS ?? 6));
|
|
908
|
-
MAX_AUGMENT_PAYLOAD_CHARS = Math.max(4000, Number(process.env.UNBROWSE_AGENT_SEMANTIC_MAX_PAYLOAD_CHARS ?? 24000));
|
|
909
|
-
GENERIC_SEMANTIC_TYPES = new Set(["identifier", "input", "resource", "entity", "item"]);
|
|
910
|
-
});
|
|
911
|
-
|
|
912
911
|
// ../../src/execution/search-forms.ts
|
|
913
912
|
var SEARCH_FIELD_NAMES, LOGIN_FIELD_NAMES, SUPPORTED_INPUT_TYPES;
|
|
914
913
|
var init_search_forms = __esm(() => {
|
|
@@ -971,7 +970,7 @@ var init_schema_review = __esm(() => {
|
|
|
971
970
|
});
|
|
972
971
|
|
|
973
972
|
// ../../src/indexer/index.ts
|
|
974
|
-
import { join as
|
|
973
|
+
import { join as join8 } from "node:path";
|
|
975
974
|
var SKILL_SNAPSHOT_DIR, indexInFlight, pendingIndexJobs;
|
|
976
975
|
var init_indexer = __esm(async () => {
|
|
977
976
|
init_graph();
|
|
@@ -986,7 +985,7 @@ var init_indexer = __esm(async () => {
|
|
|
986
985
|
init_graph();
|
|
987
986
|
init_schema_review();
|
|
988
987
|
await init_orchestrator();
|
|
989
|
-
SKILL_SNAPSHOT_DIR = process.env.UNBROWSE_SKILL_SNAPSHOT_DIR ??
|
|
988
|
+
SKILL_SNAPSHOT_DIR = process.env.UNBROWSE_SKILL_SNAPSHOT_DIR ?? join8(process.env.HOME ?? "/tmp", ".unbrowse", "skill-snapshots");
|
|
990
989
|
indexInFlight = new Map;
|
|
991
990
|
pendingIndexJobs = new Map;
|
|
992
991
|
});
|
|
@@ -1024,6 +1023,7 @@ var init_execution = __esm(async () => {
|
|
|
1024
1023
|
init_capture();
|
|
1025
1024
|
init_reverse_engineer();
|
|
1026
1025
|
init_bundle_scanner();
|
|
1026
|
+
init_token_resolver();
|
|
1027
1027
|
init_marketplace();
|
|
1028
1028
|
init_runtime();
|
|
1029
1029
|
init_transform();
|
|
@@ -1034,7 +1034,6 @@ var init_execution = __esm(async () => {
|
|
|
1034
1034
|
init_domain();
|
|
1035
1035
|
init_extraction();
|
|
1036
1036
|
init_graph();
|
|
1037
|
-
init_agent_augment();
|
|
1038
1037
|
init_logger();
|
|
1039
1038
|
init_version();
|
|
1040
1039
|
init_search_forms();
|
|
@@ -1163,8 +1162,8 @@ var init_routing_telemetry = __esm(() => {
|
|
|
1163
1162
|
});
|
|
1164
1163
|
// ../../src/orchestrator/index.ts
|
|
1165
1164
|
import { nanoid as nanoid9 } from "nanoid";
|
|
1166
|
-
import { existsSync as
|
|
1167
|
-
import { dirname as
|
|
1165
|
+
import { existsSync as existsSync10, writeFileSync as writeFileSync3, readFileSync as readFileSync6, mkdirSync as mkdirSync5, readdirSync as readdirSync3 } from "node:fs";
|
|
1166
|
+
import { dirname as dirname3, join as join9 } from "node:path";
|
|
1168
1167
|
var LIVE_CAPTURE_TIMEOUT_MS, capturedDomainCache, captureInFlight, captureDomainLocks, skillRouteCache, ROUTE_CACHE_FILE, SKILL_SNAPSHOT_DIR2, domainSkillCache, DOMAIN_CACHE_FILE, _routeCacheDirty = false, routeCacheFlushTimer, routeResultCache, ROUTE_CACHE_TTL, MARKETPLACE_HYDRATE_LIMIT, MARKETPLACE_GET_SKILL_TIMEOUT_MS, MARKETPLACE_DOMAIN_SEARCH_K, MARKETPLACE_GLOBAL_SEARCH_K, SEARCH_INTENT_STOPWORDS;
|
|
1169
1168
|
var init_orchestrator = __esm(async () => {
|
|
1170
1169
|
init_client();
|
|
@@ -1194,13 +1193,13 @@ var init_orchestrator = __esm(async () => {
|
|
|
1194
1193
|
captureInFlight = new Map;
|
|
1195
1194
|
captureDomainLocks = new Map;
|
|
1196
1195
|
skillRouteCache = new Map;
|
|
1197
|
-
ROUTE_CACHE_FILE =
|
|
1198
|
-
SKILL_SNAPSHOT_DIR2 = process.env.UNBROWSE_SKILL_SNAPSHOT_DIR ??
|
|
1196
|
+
ROUTE_CACHE_FILE = join9(process.env.HOME ?? "/tmp", ".unbrowse", "route-cache.json");
|
|
1197
|
+
SKILL_SNAPSHOT_DIR2 = process.env.UNBROWSE_SKILL_SNAPSHOT_DIR ?? join9(process.env.HOME ?? "/tmp", ".unbrowse", "skill-snapshots");
|
|
1199
1198
|
domainSkillCache = new Map;
|
|
1200
|
-
DOMAIN_CACHE_FILE =
|
|
1199
|
+
DOMAIN_CACHE_FILE = join9(process.env.HOME ?? "/tmp", ".unbrowse", "domain-skill-cache.json");
|
|
1201
1200
|
try {
|
|
1202
|
-
if (
|
|
1203
|
-
const data = JSON.parse(
|
|
1201
|
+
if (existsSync10(DOMAIN_CACHE_FILE)) {
|
|
1202
|
+
const data = JSON.parse(readFileSync6(DOMAIN_CACHE_FILE, "utf-8"));
|
|
1204
1203
|
for (const [k, v] of Object.entries(data)) {
|
|
1205
1204
|
const entry = v;
|
|
1206
1205
|
if (Date.now() - entry.ts < 7 * 24 * 60 * 60000) {
|
|
@@ -1215,17 +1214,17 @@ var init_orchestrator = __esm(async () => {
|
|
|
1215
1214
|
return;
|
|
1216
1215
|
_routeCacheDirty = false;
|
|
1217
1216
|
try {
|
|
1218
|
-
const dir =
|
|
1219
|
-
if (!
|
|
1220
|
-
|
|
1217
|
+
const dir = dirname3(ROUTE_CACHE_FILE);
|
|
1218
|
+
if (!existsSync10(dir))
|
|
1219
|
+
mkdirSync5(dir, { recursive: true });
|
|
1221
1220
|
const entries = Object.fromEntries(skillRouteCache);
|
|
1222
1221
|
writeFileSync3(ROUTE_CACHE_FILE, JSON.stringify(entries), "utf-8");
|
|
1223
1222
|
} catch {}
|
|
1224
1223
|
}, 5000);
|
|
1225
1224
|
routeCacheFlushTimer.unref?.();
|
|
1226
1225
|
try {
|
|
1227
|
-
if (
|
|
1228
|
-
const data = JSON.parse(
|
|
1226
|
+
if (existsSync10(ROUTE_CACHE_FILE)) {
|
|
1227
|
+
const data = JSON.parse(readFileSync6(ROUTE_CACHE_FILE, "utf-8"));
|
|
1229
1228
|
for (const [k, v] of Object.entries(data)) {
|
|
1230
1229
|
const entry = v;
|
|
1231
1230
|
if (Date.now() - entry.ts < 24 * 60 * 60000) {
|
|
@@ -1321,18 +1320,18 @@ __export(exports_wallet, {
|
|
|
1321
1320
|
getWalletContext: () => getWalletContext2,
|
|
1322
1321
|
checkWalletConfigured: () => checkWalletConfigured2
|
|
1323
1322
|
});
|
|
1324
|
-
import { existsSync as
|
|
1325
|
-
import { homedir as
|
|
1326
|
-
import { join as
|
|
1323
|
+
import { existsSync as existsSync14, readFileSync as readFileSync9 } from "node:fs";
|
|
1324
|
+
import { homedir as homedir6 } from "node:os";
|
|
1325
|
+
import { join as join11 } from "node:path";
|
|
1327
1326
|
function asNonEmptyString2(value) {
|
|
1328
1327
|
return typeof value === "string" && value.trim() ? value.trim() : undefined;
|
|
1329
1328
|
}
|
|
1330
1329
|
function getLobsterWalletFromLocalConfig2() {
|
|
1331
|
-
const agentsPath =
|
|
1332
|
-
if (!
|
|
1330
|
+
const agentsPath = join11(process.env.HOME || homedir6(), ".lobster", "agents.json");
|
|
1331
|
+
if (!existsSync14(agentsPath))
|
|
1333
1332
|
return;
|
|
1334
1333
|
try {
|
|
1335
|
-
const raw = JSON.parse(
|
|
1334
|
+
const raw = JSON.parse(readFileSync9(agentsPath, "utf8"));
|
|
1336
1335
|
const activeAgentId = asNonEmptyString2(raw.activeAgentId);
|
|
1337
1336
|
const activeAgent = Array.isArray(raw.agents) ? raw.agents.find((agent) => asNonEmptyString2(agent.id) === activeAgentId) : activeAgentId ? raw.agents?.[activeAgentId] : undefined;
|
|
1338
1337
|
return asNonEmptyString2(activeAgent?.authorizedWallets?.solana) ?? asNonEmptyString2(activeAgent?.walletAddress) ?? asNonEmptyString2(activeAgent?.wallet_address);
|
|
@@ -1380,7 +1379,7 @@ init_wallet();
|
|
|
1380
1379
|
init_telemetry_attribution();
|
|
1381
1380
|
import { readFileSync as readFileSync3, writeFileSync, existsSync as existsSync4, mkdirSync, readdirSync as readdirSync2 } from "fs";
|
|
1382
1381
|
import { join as join4 } from "path";
|
|
1383
|
-
import { homedir as homedir3, hostname } from "os";
|
|
1382
|
+
import { homedir as homedir3, hostname, release as osRelease } from "os";
|
|
1384
1383
|
import { randomBytes, createHash as createHash2 } from "crypto";
|
|
1385
1384
|
import { createInterface } from "readline";
|
|
1386
1385
|
var API_URL = process.env.UNBROWSE_BACKEND_URL || DEFAULT_BACKEND_URL;
|
|
@@ -1573,9 +1572,19 @@ async function recordInstallTelemetryEvent(source, options) {
|
|
|
1573
1572
|
skill_version: options?.skillVersion,
|
|
1574
1573
|
status: options?.status ?? "installed",
|
|
1575
1574
|
created_at: createdAt,
|
|
1576
|
-
properties: mergeTelemetryProperties(options?.properties, getTelemetryAttribution())
|
|
1575
|
+
properties: mergeTelemetryProperties({ ...getRuntimeContext(), ...options?.properties }, getTelemetryAttribution())
|
|
1577
1576
|
});
|
|
1578
1577
|
}
|
|
1578
|
+
function getRuntimeContext() {
|
|
1579
|
+
return {
|
|
1580
|
+
cli_version: PACKAGE_VERSION,
|
|
1581
|
+
code_hash: CODE_HASH,
|
|
1582
|
+
node_version: process.version,
|
|
1583
|
+
platform: process.platform,
|
|
1584
|
+
arch: process.arch,
|
|
1585
|
+
os_release: osRelease()
|
|
1586
|
+
};
|
|
1587
|
+
}
|
|
1579
1588
|
async function recordFunnelTelemetryEvent(name, options) {
|
|
1580
1589
|
const createdAt = options?.createdAt ?? new Date().toISOString();
|
|
1581
1590
|
const landingToken = getLandingToken();
|
|
@@ -1587,7 +1596,7 @@ async function recordFunnelTelemetryEvent(name, options) {
|
|
|
1587
1596
|
source: options?.source ?? "cli",
|
|
1588
1597
|
host_type: options?.hostType ?? detectTelemetryHostType(),
|
|
1589
1598
|
created_at: createdAt,
|
|
1590
|
-
properties: mergeTelemetryProperties(options?.properties, getTelemetryAttribution())
|
|
1599
|
+
properties: mergeTelemetryProperties({ ...getRuntimeContext(), ...options?.properties }, getTelemetryAttribution())
|
|
1591
1600
|
});
|
|
1592
1601
|
}
|
|
1593
1602
|
var EMAIL_RE = /^[^\s@]+@[^\s@]+\.[^\s@]+$/i;
|
|
@@ -1619,6 +1628,10 @@ function getApiKey() {
|
|
|
1619
1628
|
}
|
|
1620
1629
|
return "";
|
|
1621
1630
|
}
|
|
1631
|
+
function getAgentId() {
|
|
1632
|
+
const config = loadConfig();
|
|
1633
|
+
return config?.agent_id ?? null;
|
|
1634
|
+
}
|
|
1622
1635
|
var API_TIMEOUT_MS = parseInt(process.env.UNBROWSE_API_TIMEOUT ?? "8000", 10);
|
|
1623
1636
|
var PUBLISH_TIMEOUT_MS = parseInt(process.env.UNBROWSE_PUBLISH_TIMEOUT ?? "30000", 10);
|
|
1624
1637
|
async function validateApiKey(key) {
|
|
@@ -1930,6 +1943,170 @@ async function syncAgentWallet(wallet = getLocalWalletContext()) {
|
|
|
1930
1943
|
return;
|
|
1931
1944
|
saveConfig({ ...config, ...wallet });
|
|
1932
1945
|
}
|
|
1946
|
+
async function getTransactionHistory(agentId) {
|
|
1947
|
+
return api("GET", `/v1/transactions/consumer/${agentId}`);
|
|
1948
|
+
}
|
|
1949
|
+
async function getCreatorEarnings(agentId) {
|
|
1950
|
+
return api("GET", `/v1/transactions/creator/${agentId}`);
|
|
1951
|
+
}
|
|
1952
|
+
|
|
1953
|
+
// ../../src/impact-log.ts
|
|
1954
|
+
import { existsSync as existsSync5, mkdirSync as mkdirSync2, appendFileSync, statSync, readFileSync as readFileSync4, renameSync, unlinkSync } from "node:fs";
|
|
1955
|
+
import { homedir as homedir4 } from "node:os";
|
|
1956
|
+
import { dirname as dirname2, join as join5 } from "node:path";
|
|
1957
|
+
var MAX_LOG_BYTES = 5 * 1024 * 1024;
|
|
1958
|
+
var MAX_ROTATIONS = 3;
|
|
1959
|
+
function getLogDir() {
|
|
1960
|
+
if (process.env.UNBROWSE_CONFIG_DIR)
|
|
1961
|
+
return process.env.UNBROWSE_CONFIG_DIR;
|
|
1962
|
+
const profile = process.env.UNBROWSE_PROFILE?.trim();
|
|
1963
|
+
return profile ? join5(homedir4(), ".unbrowse", "profiles", profile) : join5(homedir4(), ".unbrowse");
|
|
1964
|
+
}
|
|
1965
|
+
function getImpactLogPath() {
|
|
1966
|
+
return join5(getLogDir(), "impact-log.jsonl");
|
|
1967
|
+
}
|
|
1968
|
+
function ensureDir(path) {
|
|
1969
|
+
const dir = dirname2(path);
|
|
1970
|
+
if (!existsSync5(dir))
|
|
1971
|
+
mkdirSync2(dir, { recursive: true });
|
|
1972
|
+
}
|
|
1973
|
+
function rotateIfNeeded(path) {
|
|
1974
|
+
try {
|
|
1975
|
+
if (!existsSync5(path))
|
|
1976
|
+
return;
|
|
1977
|
+
const size = statSync(path).size;
|
|
1978
|
+
if (size < MAX_LOG_BYTES)
|
|
1979
|
+
return;
|
|
1980
|
+
for (let i = MAX_ROTATIONS;i >= 1; i--) {
|
|
1981
|
+
const older = `${path}.${i}`;
|
|
1982
|
+
if (!existsSync5(older))
|
|
1983
|
+
continue;
|
|
1984
|
+
if (i === MAX_ROTATIONS) {
|
|
1985
|
+
try {
|
|
1986
|
+
unlinkSync(older);
|
|
1987
|
+
} catch {}
|
|
1988
|
+
} else {
|
|
1989
|
+
try {
|
|
1990
|
+
renameSync(older, `${path}.${i + 1}`);
|
|
1991
|
+
} catch {}
|
|
1992
|
+
}
|
|
1993
|
+
}
|
|
1994
|
+
renameSync(path, `${path}.1`);
|
|
1995
|
+
} catch {}
|
|
1996
|
+
}
|
|
1997
|
+
function appendImpact(entry) {
|
|
1998
|
+
try {
|
|
1999
|
+
const hasSignal = (entry.time_saved_ms ?? 0) > 0 || (entry.tokens_saved ?? 0) > 0 || (entry.cost_saved_uc ?? 0) > 0 || entry.browser_avoided === true;
|
|
2000
|
+
if (!hasSignal)
|
|
2001
|
+
return;
|
|
2002
|
+
const path = getImpactLogPath();
|
|
2003
|
+
ensureDir(path);
|
|
2004
|
+
rotateIfNeeded(path);
|
|
2005
|
+
appendFileSync(path, JSON.stringify(entry) + `
|
|
2006
|
+
`, "utf8");
|
|
2007
|
+
} catch {}
|
|
2008
|
+
}
|
|
2009
|
+
function impactFromResult(command, result, extras = {}) {
|
|
2010
|
+
if (!result || typeof result !== "object")
|
|
2011
|
+
return null;
|
|
2012
|
+
const r = result;
|
|
2013
|
+
const impact = r.impact ?? null;
|
|
2014
|
+
if (!impact || typeof impact !== "object")
|
|
2015
|
+
return null;
|
|
2016
|
+
const num = (v) => typeof v === "number" && Number.isFinite(v) ? v : undefined;
|
|
2017
|
+
return {
|
|
2018
|
+
ts: new Date().toISOString(),
|
|
2019
|
+
command,
|
|
2020
|
+
source: typeof impact.source === "string" ? impact.source : undefined,
|
|
2021
|
+
domain: extras.domain,
|
|
2022
|
+
intent: extras.intent,
|
|
2023
|
+
skill_id: extras.skill_id ?? (typeof r.skill_id === "string" ? r.skill_id : undefined),
|
|
2024
|
+
endpoint_id: extras.endpoint_id ?? (typeof r.endpoint_id === "string" ? r.endpoint_id : undefined),
|
|
2025
|
+
time_saved_ms: num(impact.time_saved_ms),
|
|
2026
|
+
time_saved_pct: num(impact.time_saved_pct),
|
|
2027
|
+
tokens_saved: num(impact.tokens_saved),
|
|
2028
|
+
tokens_saved_pct: num(impact.tokens_saved_pct),
|
|
2029
|
+
cost_saved_uc: num(impact.cost_saved_uc),
|
|
2030
|
+
browser_avoided: impact.browser_avoided === true,
|
|
2031
|
+
success: r.error == null
|
|
2032
|
+
};
|
|
2033
|
+
}
|
|
2034
|
+
function readImpactSummary() {
|
|
2035
|
+
const path = getImpactLogPath();
|
|
2036
|
+
const summary = {
|
|
2037
|
+
total_runs: 0,
|
|
2038
|
+
successful_runs: 0,
|
|
2039
|
+
browser_avoided_runs: 0,
|
|
2040
|
+
total_time_saved_ms: 0,
|
|
2041
|
+
total_tokens_saved: 0,
|
|
2042
|
+
total_cost_saved_uc: 0,
|
|
2043
|
+
avg_time_saved_pct: 0,
|
|
2044
|
+
avg_tokens_saved_pct: 0,
|
|
2045
|
+
by_source: {},
|
|
2046
|
+
first_entry_at: null,
|
|
2047
|
+
last_entry_at: null
|
|
2048
|
+
};
|
|
2049
|
+
const files = [];
|
|
2050
|
+
for (let i = MAX_ROTATIONS;i >= 1; i--) {
|
|
2051
|
+
const rotated = `${path}.${i}`;
|
|
2052
|
+
if (existsSync5(rotated))
|
|
2053
|
+
files.push(rotated);
|
|
2054
|
+
}
|
|
2055
|
+
if (existsSync5(path))
|
|
2056
|
+
files.push(path);
|
|
2057
|
+
if (files.length === 0)
|
|
2058
|
+
return summary;
|
|
2059
|
+
let timePctSum = 0;
|
|
2060
|
+
let timePctCount = 0;
|
|
2061
|
+
let tokenPctSum = 0;
|
|
2062
|
+
let tokenPctCount = 0;
|
|
2063
|
+
for (const file of files) {
|
|
2064
|
+
let raw;
|
|
2065
|
+
try {
|
|
2066
|
+
raw = readFileSync4(file, "utf8");
|
|
2067
|
+
} catch {
|
|
2068
|
+
continue;
|
|
2069
|
+
}
|
|
2070
|
+
for (const line of raw.split(`
|
|
2071
|
+
`)) {
|
|
2072
|
+
const trimmed = line.trim();
|
|
2073
|
+
if (!trimmed)
|
|
2074
|
+
continue;
|
|
2075
|
+
let e;
|
|
2076
|
+
try {
|
|
2077
|
+
e = JSON.parse(trimmed);
|
|
2078
|
+
} catch {
|
|
2079
|
+
continue;
|
|
2080
|
+
}
|
|
2081
|
+
summary.total_runs += 1;
|
|
2082
|
+
if (e.success !== false)
|
|
2083
|
+
summary.successful_runs += 1;
|
|
2084
|
+
if (e.browser_avoided)
|
|
2085
|
+
summary.browser_avoided_runs += 1;
|
|
2086
|
+
summary.total_time_saved_ms += e.time_saved_ms ?? 0;
|
|
2087
|
+
summary.total_tokens_saved += e.tokens_saved ?? 0;
|
|
2088
|
+
summary.total_cost_saved_uc += e.cost_saved_uc ?? 0;
|
|
2089
|
+
if (typeof e.time_saved_pct === "number") {
|
|
2090
|
+
timePctSum += e.time_saved_pct;
|
|
2091
|
+
timePctCount += 1;
|
|
2092
|
+
}
|
|
2093
|
+
if (typeof e.tokens_saved_pct === "number") {
|
|
2094
|
+
tokenPctSum += e.tokens_saved_pct;
|
|
2095
|
+
tokenPctCount += 1;
|
|
2096
|
+
}
|
|
2097
|
+
if (e.source) {
|
|
2098
|
+
summary.by_source[e.source] = (summary.by_source[e.source] ?? 0) + 1;
|
|
2099
|
+
}
|
|
2100
|
+
if (!summary.first_entry_at || e.ts < summary.first_entry_at)
|
|
2101
|
+
summary.first_entry_at = e.ts;
|
|
2102
|
+
if (!summary.last_entry_at || e.ts > summary.last_entry_at)
|
|
2103
|
+
summary.last_entry_at = e.ts;
|
|
2104
|
+
}
|
|
2105
|
+
}
|
|
2106
|
+
summary.avg_time_saved_pct = timePctCount > 0 ? Math.round(timePctSum / timePctCount) : 0;
|
|
2107
|
+
summary.avg_tokens_saved_pct = tokenPctCount > 0 ? Math.round(tokenPctSum / tokenPctCount) : 0;
|
|
2108
|
+
return summary;
|
|
2109
|
+
}
|
|
1933
2110
|
|
|
1934
2111
|
// ../../src/cli/shortcuts.ts
|
|
1935
2112
|
var linkedin = {
|
|
@@ -2130,7 +2307,7 @@ function buildDepsMetadata(pack, taskName) {
|
|
|
2130
2307
|
init_paths();
|
|
2131
2308
|
init_supervisor();
|
|
2132
2309
|
init_version();
|
|
2133
|
-
import { openSync, readFileSync as
|
|
2310
|
+
import { existsSync as existsSync7, openSync, readFileSync as readFileSync5, unlinkSync as unlinkSync2, writeFileSync as writeFileSync2 } from "node:fs";
|
|
2134
2311
|
import path2 from "node:path";
|
|
2135
2312
|
import { spawn } from "node:child_process";
|
|
2136
2313
|
function isServerVersionMismatch(runningVersion, installedVersion, runningCodeHash, installedCodeHash) {
|
|
@@ -2168,14 +2345,14 @@ function isPidAlive(pid) {
|
|
|
2168
2345
|
}
|
|
2169
2346
|
function readPidState(pidFile) {
|
|
2170
2347
|
try {
|
|
2171
|
-
return JSON.parse(
|
|
2348
|
+
return JSON.parse(readFileSync5(pidFile, "utf-8"));
|
|
2172
2349
|
} catch {
|
|
2173
2350
|
return null;
|
|
2174
2351
|
}
|
|
2175
2352
|
}
|
|
2176
2353
|
function clearStalePidFile(pidFile) {
|
|
2177
2354
|
try {
|
|
2178
|
-
|
|
2355
|
+
unlinkSync2(pidFile);
|
|
2179
2356
|
} catch {}
|
|
2180
2357
|
}
|
|
2181
2358
|
function deriveListenEnv(baseUrl) {
|
|
@@ -2196,6 +2373,10 @@ function getServerSpawnSpec(metaUrl, entrypoint = resolveSiblingEntrypoint(metaU
|
|
|
2196
2373
|
recordedEntrypoint: `${process.execPath} serve`
|
|
2197
2374
|
};
|
|
2198
2375
|
}
|
|
2376
|
+
const serverJs = path2.join(path2.dirname(entrypoint), "server.js");
|
|
2377
|
+
if (existsSync7(serverJs) && path2.basename(entrypoint) !== "server.js") {
|
|
2378
|
+
entrypoint = serverJs;
|
|
2379
|
+
}
|
|
2199
2380
|
return {
|
|
2200
2381
|
command: process.execPath,
|
|
2201
2382
|
args: runtimeArgsForEntrypoint(metaUrl, entrypoint),
|
|
@@ -2209,7 +2390,7 @@ function spawnServer(baseUrl, metaUrl, pidFile, restartCount = 0) {
|
|
|
2209
2390
|
const entrypoint = resolveSiblingEntrypoint(metaUrl, "index");
|
|
2210
2391
|
const spawnSpec = getServerSpawnSpec(metaUrl, entrypoint);
|
|
2211
2392
|
const logFile = getServerAutostartLogFile();
|
|
2212
|
-
|
|
2393
|
+
ensureDir2(path2.dirname(logFile));
|
|
2213
2394
|
const logFd = openSync(logFile, "a");
|
|
2214
2395
|
const child = spawn(spawnSpec.command, spawnSpec.args, {
|
|
2215
2396
|
cwd: spawnSpec.cwd,
|
|
@@ -2341,7 +2522,7 @@ async function restartServer(baseUrl, metaUrl) {
|
|
|
2341
2522
|
}
|
|
2342
2523
|
|
|
2343
2524
|
// ../../src/runtime/paths.ts
|
|
2344
|
-
import { existsSync as
|
|
2525
|
+
import { existsSync as existsSync8, mkdirSync as mkdirSync4, realpathSync as realpathSync2 } from "node:fs";
|
|
2345
2526
|
import path3 from "node:path";
|
|
2346
2527
|
import { createRequire as createRequire3 } from "node:module";
|
|
2347
2528
|
import { fileURLToPath as fileURLToPath3, pathToFileURL as pathToFileURL2 } from "node:url";
|
|
@@ -2361,7 +2542,7 @@ function runtimeArgsForEntrypoint2(metaUrl, entrypoint) {
|
|
|
2361
2542
|
const req = createRequire3(metaUrl);
|
|
2362
2543
|
const tsxPkg = req.resolve("tsx/package.json");
|
|
2363
2544
|
const tsxLoader = path3.join(path3.dirname(tsxPkg), "dist", "loader.mjs");
|
|
2364
|
-
if (
|
|
2545
|
+
if (existsSync8(tsxLoader))
|
|
2365
2546
|
return ["--import", pathToFileURL2(tsxLoader).href, entrypoint];
|
|
2366
2547
|
} catch {}
|
|
2367
2548
|
return ["--import", "tsx", entrypoint];
|
|
@@ -2391,8 +2572,8 @@ init_publish();
|
|
|
2391
2572
|
init_settings();
|
|
2392
2573
|
init_graph();
|
|
2393
2574
|
init_schema_review();
|
|
2394
|
-
import { join as
|
|
2395
|
-
var SKILL_SNAPSHOT_DIR3 = process.env.UNBROWSE_SKILL_SNAPSHOT_DIR ??
|
|
2575
|
+
import { join as join10 } from "node:path";
|
|
2576
|
+
var SKILL_SNAPSHOT_DIR3 = process.env.UNBROWSE_SKILL_SNAPSHOT_DIR ?? join10(process.env.HOME ?? "/tmp", ".unbrowse", "skill-snapshots");
|
|
2396
2577
|
var indexInFlight2 = new Map;
|
|
2397
2578
|
var pendingIndexJobs2 = new Map;
|
|
2398
2579
|
async function drainPendingIndexJobs() {
|
|
@@ -2430,13 +2611,13 @@ init_client2();
|
|
|
2430
2611
|
init_logger();
|
|
2431
2612
|
init_wallet();
|
|
2432
2613
|
import { execFileSync as execFileSync3 } from "node:child_process";
|
|
2433
|
-
import { existsSync as
|
|
2614
|
+
import { existsSync as existsSync12, mkdirSync as mkdirSync7, writeFileSync as writeFileSync5 } from "node:fs";
|
|
2434
2615
|
import os4 from "node:os";
|
|
2435
2616
|
import path7 from "node:path";
|
|
2436
2617
|
|
|
2437
2618
|
// ../../src/runtime/update-hints.ts
|
|
2438
2619
|
init_paths();
|
|
2439
|
-
import { existsSync as
|
|
2620
|
+
import { existsSync as existsSync11, mkdirSync as mkdirSync6, readFileSync as readFileSync7, writeFileSync as writeFileSync4 } from "node:fs";
|
|
2440
2621
|
import os3 from "node:os";
|
|
2441
2622
|
import path6 from "node:path";
|
|
2442
2623
|
var DEFAULT_INTERVAL_MS = 12 * 60 * 60 * 1000;
|
|
@@ -2449,20 +2630,20 @@ function getConfigDir2() {
|
|
|
2449
2630
|
return process.env.UNBROWSE_CONFIG_DIR;
|
|
2450
2631
|
return path6.join(getHomeDir(), ".unbrowse");
|
|
2451
2632
|
}
|
|
2452
|
-
function
|
|
2453
|
-
if (!
|
|
2454
|
-
|
|
2633
|
+
function ensureDir3(dir) {
|
|
2634
|
+
if (!existsSync11(dir))
|
|
2635
|
+
mkdirSync6(dir, { recursive: true });
|
|
2455
2636
|
return dir;
|
|
2456
2637
|
}
|
|
2457
2638
|
function readJsonFile(file) {
|
|
2458
2639
|
try {
|
|
2459
|
-
return JSON.parse(
|
|
2640
|
+
return JSON.parse(readFileSync7(file, "utf8"));
|
|
2460
2641
|
} catch {
|
|
2461
2642
|
return null;
|
|
2462
2643
|
}
|
|
2463
2644
|
}
|
|
2464
2645
|
function writeJsonFile(file, value) {
|
|
2465
|
-
|
|
2646
|
+
ensureDir3(path6.dirname(file));
|
|
2466
2647
|
writeFileSync4(file, `${JSON.stringify(value, null, 2)}
|
|
2467
2648
|
`);
|
|
2468
2649
|
}
|
|
@@ -2473,7 +2654,7 @@ function detectRepoRoot(start2) {
|
|
|
2473
2654
|
let dir = path6.resolve(start2);
|
|
2474
2655
|
const root = path6.parse(dir).root;
|
|
2475
2656
|
while (dir !== root) {
|
|
2476
|
-
if (
|
|
2657
|
+
if (existsSync11(path6.join(dir, ".git")))
|
|
2477
2658
|
return dir;
|
|
2478
2659
|
dir = path6.dirname(dir);
|
|
2479
2660
|
}
|
|
@@ -2552,13 +2733,13 @@ codex_hooks = true
|
|
|
2552
2733
|
}
|
|
2553
2734
|
function writeCodexHook(metaUrl) {
|
|
2554
2735
|
const configPath = getCodexConfigPath();
|
|
2555
|
-
if (!
|
|
2736
|
+
if (!existsSync11(path6.dirname(configPath))) {
|
|
2556
2737
|
return { host: "codex", action: "not-detected", config_file: configPath };
|
|
2557
2738
|
}
|
|
2558
2739
|
try {
|
|
2559
2740
|
const hookScript = getHookScriptPath(metaUrl).replace(/\\/g, "/");
|
|
2560
|
-
const fileExistsBefore =
|
|
2561
|
-
let content = fileExistsBefore ?
|
|
2741
|
+
const fileExistsBefore = existsSync11(configPath);
|
|
2742
|
+
let content = fileExistsBefore ? readFileSync7(configPath, "utf8") : "";
|
|
2562
2743
|
const previous = content;
|
|
2563
2744
|
content = ensureCodexHooksFeature(content);
|
|
2564
2745
|
if (!content.includes("unbrowse-update-hint.mjs")) {
|
|
@@ -2592,13 +2773,13 @@ command = ${JSON.stringify(command)}
|
|
|
2592
2773
|
}
|
|
2593
2774
|
function writeClaudeHook(metaUrl) {
|
|
2594
2775
|
const settingsPath = getClaudeSettingsPath();
|
|
2595
|
-
if (!
|
|
2776
|
+
if (!existsSync11(path6.dirname(settingsPath))) {
|
|
2596
2777
|
return { host: "claude", action: "not-detected", config_file: settingsPath };
|
|
2597
2778
|
}
|
|
2598
2779
|
try {
|
|
2599
2780
|
const hookScript = getHookScriptPath(metaUrl).replace(/\\/g, "/");
|
|
2600
2781
|
const command = `node "${hookScript}"`;
|
|
2601
|
-
const fileExistsBefore =
|
|
2782
|
+
const fileExistsBefore = existsSync11(settingsPath);
|
|
2602
2783
|
const settings = readJsonFile(settingsPath) ?? {};
|
|
2603
2784
|
settings.hooks ??= {};
|
|
2604
2785
|
settings.hooks.SessionStart ??= [];
|
|
@@ -2663,7 +2844,7 @@ function getOpenCodeProjectCommandsDir(cwd) {
|
|
|
2663
2844
|
return path7.join(cwd, ".opencode", "commands");
|
|
2664
2845
|
}
|
|
2665
2846
|
function detectOpenCode(cwd) {
|
|
2666
|
-
return hasBinary("opencode") ||
|
|
2847
|
+
return hasBinary("opencode") || existsSync12(path7.join(resolveConfigHome(), "opencode")) || existsSync12(path7.join(cwd, ".opencode"));
|
|
2667
2848
|
}
|
|
2668
2849
|
function renderOpenCodeCommand() {
|
|
2669
2850
|
return `---
|
|
@@ -2691,12 +2872,12 @@ function writeOpenCodeCommand(scope, cwd) {
|
|
|
2691
2872
|
if (scope === "auto" && !detected) {
|
|
2692
2873
|
return { detected: false, action: "not-detected", scope: "off" };
|
|
2693
2874
|
}
|
|
2694
|
-
const resolvedScope = scope === "project" ? "project" : scope === "global" ? "global" :
|
|
2875
|
+
const resolvedScope = scope === "project" ? "project" : scope === "global" ? "global" : existsSync12(path7.join(cwd, ".opencode")) ? "project" : "global";
|
|
2695
2876
|
const commandsDir = resolvedScope === "project" ? getOpenCodeProjectCommandsDir(cwd) : getOpenCodeGlobalCommandsDir();
|
|
2696
|
-
const commandFile = path7.join(
|
|
2877
|
+
const commandFile = path7.join(ensureDir2(commandsDir), "unbrowse.md");
|
|
2697
2878
|
const content = renderOpenCodeCommand();
|
|
2698
|
-
const action2 =
|
|
2699
|
-
|
|
2879
|
+
const action2 = existsSync12(commandFile) ? "updated" : "installed";
|
|
2880
|
+
mkdirSync7(path7.dirname(commandFile), { recursive: true });
|
|
2700
2881
|
writeFileSync5(commandFile, content);
|
|
2701
2882
|
return {
|
|
2702
2883
|
detected: detected || scope !== "auto",
|
|
@@ -2707,10 +2888,10 @@ function writeOpenCodeCommand(scope, cwd) {
|
|
|
2707
2888
|
}
|
|
2708
2889
|
async function ensureBrowserEngineInstalled() {
|
|
2709
2890
|
const binary = findKuriBinary();
|
|
2710
|
-
if (
|
|
2891
|
+
if (existsSync12(binary)) {
|
|
2711
2892
|
return { installed: true, action: "already-installed" };
|
|
2712
2893
|
}
|
|
2713
|
-
const sourceDir = getKuriSourceCandidates().find((candidate) =>
|
|
2894
|
+
const sourceDir = getKuriSourceCandidates().find((candidate) => existsSync12(path7.join(candidate, "build.zig")));
|
|
2714
2895
|
if (!sourceDir) {
|
|
2715
2896
|
return {
|
|
2716
2897
|
installed: false,
|
|
@@ -2732,7 +2913,7 @@ async function ensureBrowserEngineInstalled() {
|
|
|
2732
2913
|
timeout: 300000
|
|
2733
2914
|
});
|
|
2734
2915
|
const builtBinary = findKuriBinary();
|
|
2735
|
-
if (
|
|
2916
|
+
if (existsSync12(builtBinary)) {
|
|
2736
2917
|
return {
|
|
2737
2918
|
installed: true,
|
|
2738
2919
|
action: "installed",
|
|
@@ -2757,7 +2938,7 @@ async function runSetup(options) {
|
|
|
2757
2938
|
const browser = options?.installBrowser === false ? { installed: false, action: "skipped" } : await ensureBrowserEngineInstalled();
|
|
2758
2939
|
const walletCheck = checkWalletConfigured();
|
|
2759
2940
|
const skipWalletSetup = process.env.UNBROWSE_SKIP_WALLET_SETUP === "1";
|
|
2760
|
-
const lobsterInstalled = hasBinary("lobstercash") ||
|
|
2941
|
+
const lobsterInstalled = hasBinary("lobstercash") || existsSync12(path7.join(os4.homedir(), ".agents", "skills", "lobstercash", "SKILL.md"));
|
|
2761
2942
|
if (!skipWalletSetup && !walletCheck.configured && lobsterInstalled) {
|
|
2762
2943
|
console.log("[unbrowse] Crossmint lobster.cash detected but wallet not configured — running wallet setup...");
|
|
2763
2944
|
try {
|
|
@@ -2797,7 +2978,7 @@ async function runSetup(options) {
|
|
|
2797
2978
|
|
|
2798
2979
|
// ../../src/runtime/update-hints.ts
|
|
2799
2980
|
init_paths();
|
|
2800
|
-
import { existsSync as
|
|
2981
|
+
import { existsSync as existsSync13, mkdirSync as mkdirSync8, readFileSync as readFileSync8, writeFileSync as writeFileSync6 } from "node:fs";
|
|
2801
2982
|
import os5 from "node:os";
|
|
2802
2983
|
import path8 from "node:path";
|
|
2803
2984
|
var INSTALL_SCRIPT_URL = "https://unbrowse.ai/install.sh";
|
|
@@ -2810,20 +2991,20 @@ function getConfigDir3() {
|
|
|
2810
2991
|
return process.env.UNBROWSE_CONFIG_DIR;
|
|
2811
2992
|
return path8.join(getHomeDir2(), ".unbrowse");
|
|
2812
2993
|
}
|
|
2813
|
-
function
|
|
2814
|
-
if (!
|
|
2815
|
-
|
|
2994
|
+
function ensureDir4(dir) {
|
|
2995
|
+
if (!existsSync13(dir))
|
|
2996
|
+
mkdirSync8(dir, { recursive: true });
|
|
2816
2997
|
return dir;
|
|
2817
2998
|
}
|
|
2818
2999
|
function readJsonFile2(file) {
|
|
2819
3000
|
try {
|
|
2820
|
-
return JSON.parse(
|
|
3001
|
+
return JSON.parse(readFileSync8(file, "utf8"));
|
|
2821
3002
|
} catch {
|
|
2822
3003
|
return null;
|
|
2823
3004
|
}
|
|
2824
3005
|
}
|
|
2825
3006
|
function writeJsonFile2(file, value) {
|
|
2826
|
-
|
|
3007
|
+
ensureDir4(path8.dirname(file));
|
|
2827
3008
|
writeFileSync6(file, `${JSON.stringify(value, null, 2)}
|
|
2828
3009
|
`);
|
|
2829
3010
|
}
|
|
@@ -2837,7 +3018,7 @@ function detectRepoRoot2(start2) {
|
|
|
2837
3018
|
let dir = path8.resolve(start2);
|
|
2838
3019
|
const root = path8.parse(dir).root;
|
|
2839
3020
|
while (dir !== root) {
|
|
2840
|
-
if (
|
|
3021
|
+
if (existsSync13(path8.join(dir, ".git")))
|
|
2841
3022
|
return dir;
|
|
2842
3023
|
dir = path8.dirname(dir);
|
|
2843
3024
|
}
|
|
@@ -2870,7 +3051,7 @@ function detectInstallHost2(repoRoot) {
|
|
|
2870
3051
|
function getInstalledVersion(metaUrl) {
|
|
2871
3052
|
const packageRoot = getPackageRoot(metaUrl);
|
|
2872
3053
|
try {
|
|
2873
|
-
const pkg = JSON.parse(
|
|
3054
|
+
const pkg = JSON.parse(readFileSync8(path8.join(packageRoot, "package.json"), "utf8"));
|
|
2874
3055
|
return pkg.version ?? "unknown";
|
|
2875
3056
|
} catch {
|
|
2876
3057
|
return "unknown";
|
|
@@ -3118,6 +3299,14 @@ function formatSavedDuration(ms) {
|
|
|
3118
3299
|
return `${(ms / 1000).toFixed(1)}s`;
|
|
3119
3300
|
return `${ms}ms`;
|
|
3120
3301
|
}
|
|
3302
|
+
function formatCostUsd(uc) {
|
|
3303
|
+
const usd = uc / 1e6;
|
|
3304
|
+
if (usd >= 1)
|
|
3305
|
+
return `$${usd.toFixed(2)}`;
|
|
3306
|
+
if (usd >= 0.01)
|
|
3307
|
+
return `$${usd.toFixed(3)}`;
|
|
3308
|
+
return `$${usd.toFixed(4)}`;
|
|
3309
|
+
}
|
|
3121
3310
|
function emitImpactSummary(result) {
|
|
3122
3311
|
const impact = result.impact;
|
|
3123
3312
|
if (!impact)
|
|
@@ -3126,14 +3315,17 @@ function emitImpactSummary(result) {
|
|
|
3126
3315
|
const tokensSaved = typeof impact.tokens_saved === "number" ? impact.tokens_saved : 0;
|
|
3127
3316
|
const timeSavedPct = typeof impact.time_saved_pct === "number" ? impact.time_saved_pct : 0;
|
|
3128
3317
|
const tokensSavedPct = typeof impact.tokens_saved_pct === "number" ? impact.tokens_saved_pct : 0;
|
|
3318
|
+
const costSavedUc = typeof impact.cost_saved_uc === "number" ? impact.cost_saved_uc : 0;
|
|
3129
3319
|
const browserAvoided = impact.browser_avoided === true;
|
|
3130
|
-
if (timeSavedMs <= 0 && tokensSaved <= 0 && !browserAvoided)
|
|
3320
|
+
if (timeSavedMs <= 0 && tokensSaved <= 0 && costSavedUc <= 0 && !browserAvoided)
|
|
3131
3321
|
return;
|
|
3132
3322
|
const parts = [];
|
|
3133
3323
|
if (timeSavedMs > 0)
|
|
3134
3324
|
parts.push(`${formatSavedDuration(timeSavedMs)} saved (${timeSavedPct}% faster)`);
|
|
3135
3325
|
if (tokensSaved > 0)
|
|
3136
3326
|
parts.push(`${tokensSaved.toLocaleString("en-US")} tokens saved (${tokensSavedPct}% less context)`);
|
|
3327
|
+
if (costSavedUc > 0)
|
|
3328
|
+
parts.push(`${formatCostUsd(costSavedUc)} saved`);
|
|
3137
3329
|
if (browserAvoided)
|
|
3138
3330
|
parts.push("browser avoided");
|
|
3139
3331
|
info(parts.join(" \u2022 "));
|
|
@@ -3278,6 +3470,11 @@ async function cmdResolve(flags) {
|
|
|
3278
3470
|
}
|
|
3279
3471
|
result = slimTrace(result);
|
|
3280
3472
|
emitImpactSummary(result);
|
|
3473
|
+
{
|
|
3474
|
+
const entry = impactFromResult("resolve", result, { intent, domain });
|
|
3475
|
+
if (entry)
|
|
3476
|
+
appendImpact(entry);
|
|
3477
|
+
}
|
|
3281
3478
|
emitNextActionSummary(result);
|
|
3282
3479
|
const skill = result.skill;
|
|
3283
3480
|
const trace = result.trace;
|
|
@@ -3448,6 +3645,14 @@ async function cmdExecute(flags) {
|
|
|
3448
3645
|
}
|
|
3449
3646
|
result = slimTrace(result);
|
|
3450
3647
|
emitImpactSummary(result);
|
|
3648
|
+
{
|
|
3649
|
+
const entry = impactFromResult("execute", result, {
|
|
3650
|
+
skill_id: skillId,
|
|
3651
|
+
endpoint_id: typeof flags.endpoint === "string" ? flags.endpoint : undefined
|
|
3652
|
+
});
|
|
3653
|
+
if (entry)
|
|
3654
|
+
appendImpact(entry);
|
|
3655
|
+
}
|
|
3451
3656
|
emitNextActionSummary(result);
|
|
3452
3657
|
const pathFlag = flags.path;
|
|
3453
3658
|
const extractFlag = flags.extract;
|
|
@@ -3536,6 +3741,25 @@ async function cmdFeedback(flags) {
|
|
|
3536
3741
|
body.diagnostics = JSON.parse(flags.diagnostics);
|
|
3537
3742
|
output(await api2("POST", "/v1/feedback", body), !!flags.pretty);
|
|
3538
3743
|
}
|
|
3744
|
+
async function cmdAnnotate(flags) {
|
|
3745
|
+
const skillId = flags.skill;
|
|
3746
|
+
const endpointId = flags.endpoint;
|
|
3747
|
+
if (!skillId || !endpointId)
|
|
3748
|
+
die("--skill and --endpoint are required");
|
|
3749
|
+
const body = {};
|
|
3750
|
+
if (flags.text) {
|
|
3751
|
+
body.annotations = [{ text: flags.text }];
|
|
3752
|
+
}
|
|
3753
|
+
if (flags.constraint) {
|
|
3754
|
+
const parts = flags.constraint.split(":");
|
|
3755
|
+
if (parts.length >= 3) {
|
|
3756
|
+
body.constraints = [{ param: parts[0], rule: parts[1], message: parts.slice(2).join(":") }];
|
|
3757
|
+
}
|
|
3758
|
+
}
|
|
3759
|
+
if (!body.annotations && !body.constraints)
|
|
3760
|
+
die("--text or --constraint required");
|
|
3761
|
+
output(await api2("POST", `/v1/skills/${skillId}/endpoints/${endpointId}/annotate`, body), !!flags.pretty);
|
|
3762
|
+
}
|
|
3539
3763
|
async function cmdReview(flags) {
|
|
3540
3764
|
const skillId = flags.skill;
|
|
3541
3765
|
if (!skillId)
|
|
@@ -3750,6 +3974,7 @@ var CLI_REFERENCE = {
|
|
|
3750
3974
|
{ name: "resolve", usage: '--intent "..." [--domain "..."] [--url "..."] [opts]', desc: "Search cached indexed/published routes and optionally execute the top trusted endpoint" },
|
|
3751
3975
|
{ name: "execute", usage: "--skill ID --endpoint ID [opts]", desc: "Execute a specific endpoint" },
|
|
3752
3976
|
{ name: "feedback", usage: "--skill ID --endpoint ID --rating N", desc: "Submit feedback (mandatory after resolve)" },
|
|
3977
|
+
{ name: "annotate", usage: "--skill ID --endpoint ID --text 'tip' [--constraint 'param:rule:message']", desc: "Contribute best practices or constraints for an endpoint" },
|
|
3753
3978
|
{ name: "review", usage: "--skill ID --endpoints '[...]'", desc: "Push reviewed descriptions/schema metadata back to a captured skill before publish" },
|
|
3754
3979
|
{ name: "index", usage: "--skill ID", desc: "Recompute local graph/contracts/export from cached skill state only" },
|
|
3755
3980
|
{ name: "publish", usage: "--skill ID [--confirm-publish] [--endpoints '[...]']", desc: "Re-index locally, inspect publish-review metadata, then publish/share from cached skill state" },
|
|
@@ -3777,7 +4002,8 @@ var CLI_REFERENCE = {
|
|
|
3777
4002
|
{ name: "back", usage: "[--session id]", desc: "Navigate back" },
|
|
3778
4003
|
{ name: "forward", usage: "[--session id]", desc: "Navigate forward" },
|
|
3779
4004
|
{ name: "sync", usage: "[--session id]", desc: "Checkpoint current capture, keep tab open, queue background index + publish, then inspect via skill/publish review" },
|
|
3780
|
-
{ name: "close", usage: "[--session id]", desc: "Checkpoint capture, queue background index + publish, close browse session, then inspect via skill/publish review" }
|
|
4005
|
+
{ name: "close", usage: "[--session id]", desc: "Checkpoint capture, queue background index + publish, close browse session, then inspect via skill/publish review" },
|
|
4006
|
+
{ name: "stats", usage: "[--json] [--pretty]", desc: "Show lifetime time/tokens/cost saved and marketplace earnings/spending" }
|
|
3781
4007
|
],
|
|
3782
4008
|
globalFlags: [
|
|
3783
4009
|
{ flag: "--pretty", desc: "Indented JSON output" },
|
|
@@ -3818,6 +4044,131 @@ var CLI_REFERENCE = {
|
|
|
3818
4044
|
`unbrowse publish --skill abc --endpoints '[{"endpoint_id":"def","description":"Search court judgments by keywords","action_kind":"search","resource_kind":"judgment"}]'`
|
|
3819
4045
|
]
|
|
3820
4046
|
};
|
|
4047
|
+
function formatTotalDuration(ms) {
|
|
4048
|
+
if (ms >= 3600000)
|
|
4049
|
+
return `${(ms / 3600000).toFixed(1)}h`;
|
|
4050
|
+
if (ms >= 60000)
|
|
4051
|
+
return `${(ms / 60000).toFixed(1)}m`;
|
|
4052
|
+
if (ms >= 1000)
|
|
4053
|
+
return `${(ms / 1000).toFixed(1)}s`;
|
|
4054
|
+
return `${ms}ms`;
|
|
4055
|
+
}
|
|
4056
|
+
async function cmdStats(flags) {
|
|
4057
|
+
const pretty = !!flags.pretty;
|
|
4058
|
+
const jsonOnly = !!flags.json;
|
|
4059
|
+
const local = readImpactSummary();
|
|
4060
|
+
const agentId = getAgentId();
|
|
4061
|
+
let profile = null;
|
|
4062
|
+
let earnings = null;
|
|
4063
|
+
let spending = null;
|
|
4064
|
+
const remoteErrors = {};
|
|
4065
|
+
if (agentId) {
|
|
4066
|
+
const results = await Promise.allSettled([
|
|
4067
|
+
getMyProfile(),
|
|
4068
|
+
getCreatorEarnings(agentId),
|
|
4069
|
+
getTransactionHistory(agentId)
|
|
4070
|
+
]);
|
|
4071
|
+
if (results[0].status === "fulfilled")
|
|
4072
|
+
profile = results[0].value;
|
|
4073
|
+
else
|
|
4074
|
+
remoteErrors.profile = results[0].reason?.message ?? String(results[0].reason);
|
|
4075
|
+
if (results[1].status === "fulfilled")
|
|
4076
|
+
earnings = results[1].value;
|
|
4077
|
+
else
|
|
4078
|
+
remoteErrors.earnings = results[1].reason?.message ?? String(results[1].reason);
|
|
4079
|
+
if (results[2].status === "fulfilled")
|
|
4080
|
+
spending = results[2].value;
|
|
4081
|
+
else
|
|
4082
|
+
remoteErrors.spending = results[2].reason?.message ?? String(results[2].reason);
|
|
4083
|
+
} else {
|
|
4084
|
+
remoteErrors.profile = "No agent_id in local config. Run `unbrowse setup` to register.";
|
|
4085
|
+
}
|
|
4086
|
+
const earnedUsd = earnings?.ledger?.total_earned_usd ?? 0;
|
|
4087
|
+
const spentUsd = spending?.ledger?.total_spent_usd ?? 0;
|
|
4088
|
+
const netUsd = earnedUsd - spentUsd;
|
|
4089
|
+
const savedUsd = local.total_cost_saved_uc / 1e6;
|
|
4090
|
+
const payload = {
|
|
4091
|
+
agent_id: agentId,
|
|
4092
|
+
profile,
|
|
4093
|
+
impact: {
|
|
4094
|
+
total_runs: local.total_runs,
|
|
4095
|
+
successful_runs: local.successful_runs,
|
|
4096
|
+
browser_avoided_runs: local.browser_avoided_runs,
|
|
4097
|
+
total_time_saved_ms: local.total_time_saved_ms,
|
|
4098
|
+
total_time_saved_human: formatTotalDuration(local.total_time_saved_ms),
|
|
4099
|
+
total_tokens_saved: local.total_tokens_saved,
|
|
4100
|
+
total_cost_saved_usd: Number(savedUsd.toFixed(6)),
|
|
4101
|
+
avg_time_saved_pct: local.avg_time_saved_pct,
|
|
4102
|
+
avg_tokens_saved_pct: local.avg_tokens_saved_pct,
|
|
4103
|
+
by_source: local.by_source,
|
|
4104
|
+
first_entry_at: local.first_entry_at,
|
|
4105
|
+
last_entry_at: local.last_entry_at,
|
|
4106
|
+
log_path: getImpactLogPath()
|
|
4107
|
+
},
|
|
4108
|
+
earnings: {
|
|
4109
|
+
total_earned_usd: earnedUsd,
|
|
4110
|
+
total_earned_uc: earnings?.ledger?.total_earned_uc ?? 0,
|
|
4111
|
+
transaction_count: earnings?.ledger?.transaction_count ?? 0,
|
|
4112
|
+
last_transaction_at: earnings?.ledger?.last_transaction_at ?? null
|
|
4113
|
+
},
|
|
4114
|
+
spending: {
|
|
4115
|
+
total_spent_usd: spentUsd,
|
|
4116
|
+
total_spent_uc: spending?.ledger?.total_spent_uc ?? 0,
|
|
4117
|
+
transaction_count: spending?.ledger?.transaction_count ?? 0,
|
|
4118
|
+
last_transaction_at: spending?.ledger?.last_transaction_at ?? null
|
|
4119
|
+
},
|
|
4120
|
+
net_usd: netUsd,
|
|
4121
|
+
...Object.keys(remoteErrors).length > 0 ? { remote_errors: remoteErrors } : {}
|
|
4122
|
+
};
|
|
4123
|
+
if (jsonOnly) {
|
|
4124
|
+
output(payload, pretty);
|
|
4125
|
+
return;
|
|
4126
|
+
}
|
|
4127
|
+
const lines = [];
|
|
4128
|
+
lines.push("Unbrowse stats");
|
|
4129
|
+
lines.push(` agent_id: ${agentId ?? "(not registered \u2014 run `unbrowse setup`)"}`);
|
|
4130
|
+
if (profile?.name)
|
|
4131
|
+
lines.push(` name: ${profile.name}`);
|
|
4132
|
+
lines.push("");
|
|
4133
|
+
lines.push("Impact (local, this machine):");
|
|
4134
|
+
if (local.total_runs === 0) {
|
|
4135
|
+
lines.push(" No resolve/execute runs recorded yet.");
|
|
4136
|
+
lines.push(` Log file: ${getImpactLogPath()}`);
|
|
4137
|
+
} else {
|
|
4138
|
+
lines.push(` Runs: ${local.total_runs} (${local.successful_runs} successful, ${local.browser_avoided_runs} browser-avoided)`);
|
|
4139
|
+
if (local.total_time_saved_ms > 0) {
|
|
4140
|
+
lines.push(` Time saved: ${formatTotalDuration(local.total_time_saved_ms)} (avg ${local.avg_time_saved_pct}% faster)`);
|
|
4141
|
+
}
|
|
4142
|
+
if (local.total_tokens_saved > 0) {
|
|
4143
|
+
lines.push(` Tokens saved: ${local.total_tokens_saved.toLocaleString("en-US")} (avg ${local.avg_tokens_saved_pct}% less context)`);
|
|
4144
|
+
}
|
|
4145
|
+
if (savedUsd > 0) {
|
|
4146
|
+
lines.push(` Cost saved: ${formatCostUsd(local.total_cost_saved_uc)}`);
|
|
4147
|
+
}
|
|
4148
|
+
if (Object.keys(local.by_source).length > 0) {
|
|
4149
|
+
const topSources = Object.entries(local.by_source).sort((a, b) => b[1] - a[1]).slice(0, 5).map(([k, v]) => `${k}=${v}`).join(", ");
|
|
4150
|
+
lines.push(` By source: ${topSources}`);
|
|
4151
|
+
}
|
|
4152
|
+
}
|
|
4153
|
+
lines.push("");
|
|
4154
|
+
lines.push("Money (backend ledger):");
|
|
4155
|
+
if (!agentId) {
|
|
4156
|
+
lines.push(" (not registered \u2014 earnings/spending unavailable)");
|
|
4157
|
+
} else if (remoteErrors.earnings || remoteErrors.spending) {
|
|
4158
|
+
if (remoteErrors.earnings)
|
|
4159
|
+
lines.push(` earnings: error \u2014 ${remoteErrors.earnings}`);
|
|
4160
|
+
if (remoteErrors.spending)
|
|
4161
|
+
lines.push(` spending: error \u2014 ${remoteErrors.spending}`);
|
|
4162
|
+
} else {
|
|
4163
|
+
lines.push(` Earned: $${earnedUsd.toFixed(4)} (${earnings?.ledger?.transaction_count ?? 0} payouts)`);
|
|
4164
|
+
lines.push(` Spent: $${spentUsd.toFixed(4)} (${spending?.ledger?.transaction_count ?? 0} payments)`);
|
|
4165
|
+
lines.push(` Net: ${netUsd >= 0 ? "+" : ""}$${netUsd.toFixed(4)}`);
|
|
4166
|
+
}
|
|
4167
|
+
lines.push("");
|
|
4168
|
+
info(lines.join(`
|
|
4169
|
+
`));
|
|
4170
|
+
output(payload, pretty);
|
|
4171
|
+
}
|
|
3821
4172
|
function printHelp() {
|
|
3822
4173
|
const r = CLI_REFERENCE;
|
|
3823
4174
|
const lines = ["unbrowse \u2014 shell-safe CLI for the local API", ""];
|
|
@@ -4239,6 +4590,8 @@ async function main() {
|
|
|
4239
4590
|
return cmdUpgrade(flags);
|
|
4240
4591
|
if (command === "connect-chrome")
|
|
4241
4592
|
return cmdConnectChrome();
|
|
4593
|
+
if (command === "stats")
|
|
4594
|
+
return cmdStats(flags);
|
|
4242
4595
|
const KNOWN_COMMANDS = new Set([
|
|
4243
4596
|
"health",
|
|
4244
4597
|
"mcp",
|
|
@@ -4248,6 +4601,7 @@ async function main() {
|
|
|
4248
4601
|
"exec",
|
|
4249
4602
|
"feedback",
|
|
4250
4603
|
"fb",
|
|
4604
|
+
"annotate",
|
|
4251
4605
|
"review",
|
|
4252
4606
|
"index",
|
|
4253
4607
|
"publish",
|
|
@@ -4282,7 +4636,8 @@ async function main() {
|
|
|
4282
4636
|
"forward",
|
|
4283
4637
|
"sync",
|
|
4284
4638
|
"close",
|
|
4285
|
-
"connect-chrome"
|
|
4639
|
+
"connect-chrome",
|
|
4640
|
+
"stats"
|
|
4286
4641
|
]);
|
|
4287
4642
|
if (!KNOWN_COMMANDS.has(command)) {
|
|
4288
4643
|
const pack = findSitePack(command);
|
|
@@ -4318,6 +4673,8 @@ async function main() {
|
|
|
4318
4673
|
case "feedback":
|
|
4319
4674
|
case "fb":
|
|
4320
4675
|
return cmdFeedback(flags);
|
|
4676
|
+
case "annotate":
|
|
4677
|
+
return cmdAnnotate(flags);
|
|
4321
4678
|
case "review":
|
|
4322
4679
|
return cmdReview(flags);
|
|
4323
4680
|
case "index":
|
|
@@ -4378,6 +4735,8 @@ async function main() {
|
|
|
4378
4735
|
return cmdClose(flags);
|
|
4379
4736
|
case "connect-chrome":
|
|
4380
4737
|
return cmdConnectChrome();
|
|
4738
|
+
case "stats":
|
|
4739
|
+
return cmdStats(flags);
|
|
4381
4740
|
default:
|
|
4382
4741
|
info(`Unknown command: ${command}`);
|
|
4383
4742
|
printHelp();
|