tenjin-cli 0.1.0-alpha.1 → 0.1.0-alpha.2
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/NOTICE.md +33 -0
- package/README.md +164 -16
- package/dist/{_esm-ZH2J4QEH.js → _esm-C5CRWCYU.js} +2 -2
- package/dist/_esm-FEASBWRP.js +881 -0
- package/dist/buy-U35DQ6XM.js +1598 -0
- package/dist/buy-U35DQ6XM.js.map +1 -0
- package/dist/candidate-RLYCQMF5.js +127 -0
- package/dist/candidate-RLYCQMF5.js.map +1 -0
- package/dist/{ccip-UCLT5VOW.js → ccip-NQXCEK2U.js} +6 -5
- package/dist/ccip-XR5NE5QK.js +19 -0
- package/dist/chunk-27ONARHV.js +171 -0
- package/dist/chunk-27ONARHV.js.map +1 -0
- package/dist/chunk-2I4QTOLB.js +11 -0
- package/dist/chunk-2I4QTOLB.js.map +1 -0
- package/dist/chunk-3OV7E5G5.js +18 -0
- package/dist/chunk-3OV7E5G5.js.map +1 -0
- package/dist/chunk-5CLSD5YN.js +209 -0
- package/dist/chunk-5CLSD5YN.js.map +1 -0
- package/dist/chunk-7KUW4MJD.js +59 -0
- package/dist/chunk-7KUW4MJD.js.map +1 -0
- package/dist/{doctor-3QBYN46N.js → chunk-7PHSZKQS.js} +88 -93
- package/dist/chunk-7PHSZKQS.js.map +1 -0
- package/dist/chunk-CYOF7ROH.js +70 -0
- package/dist/chunk-CYOF7ROH.js.map +1 -0
- package/dist/chunk-HIVZG55D.js +204 -0
- package/dist/chunk-HIVZG55D.js.map +1 -0
- package/dist/chunk-HSDCI7OV.js +7806 -0
- package/dist/chunk-HSDCI7OV.js.map +1 -0
- package/dist/{chunk-EZROUI5U.js → chunk-IYLHQMT5.js} +85 -9
- package/dist/chunk-IYLHQMT5.js.map +1 -0
- package/dist/chunk-JPHG2JW3.js +96 -0
- package/dist/chunk-JPHG2JW3.js.map +1 -0
- package/dist/{chunk-ZPZFPVDN.js → chunk-MUBUQVC3.js} +1 -1
- package/dist/chunk-MUBUQVC3.js.map +1 -0
- package/dist/chunk-N62ROTMC.js +79 -0
- package/dist/chunk-N62ROTMC.js.map +1 -0
- package/dist/{chunk-T4LKNY7T.js → chunk-NCE5NSN6.js} +166 -11
- package/dist/chunk-NCE5NSN6.js.map +1 -0
- package/dist/{chunk-YG2DO46P.js → chunk-OYMYCW7J.js} +18 -3
- package/dist/{chunk-YG2DO46P.js.map → chunk-OYMYCW7J.js.map} +1 -1
- package/dist/chunk-QNP7H47L.js +152 -0
- package/dist/chunk-QNP7H47L.js.map +1 -0
- package/dist/{chunk-Q53IYV2G.js → chunk-QVX5MWJZ.js} +20 -17
- package/dist/{chunk-Q53IYV2G.js.map → chunk-QVX5MWJZ.js.map} +1 -1
- package/dist/{chunk-CUWUHTIL.js → chunk-RBJPAZFI.js} +16 -202
- package/dist/chunk-RBJPAZFI.js.map +1 -0
- package/dist/chunk-RRN3YTK7.js +6199 -0
- package/dist/chunk-RRN3YTK7.js.map +1 -0
- package/dist/chunk-RY4XKNV3.js +140 -0
- package/dist/chunk-RY4XKNV3.js.map +1 -0
- package/dist/chunk-S3IGX57D.js +14682 -0
- package/dist/chunk-S3IGX57D.js.map +1 -0
- package/dist/{config-CEFTL5ZL.js → chunk-TFGSOPWR.js} +115 -18
- package/dist/chunk-TFGSOPWR.js.map +1 -0
- package/dist/chunk-TLCMMYLY.js +126 -0
- package/dist/chunk-TLCMMYLY.js.map +1 -0
- package/dist/{chunk-IPOWB3G3.js → chunk-UGX7YPX2.js} +3314 -306
- package/dist/chunk-UGX7YPX2.js.map +1 -0
- package/dist/chunk-UO22YNY4.js +69 -0
- package/dist/chunk-UO22YNY4.js.map +1 -0
- package/dist/chunk-UPIEAMGH.js +160 -0
- package/dist/chunk-UPIEAMGH.js.map +1 -0
- package/dist/chunk-XJIW7USF.js +217 -0
- package/dist/chunk-XJIW7USF.js.map +1 -0
- package/dist/{chunk-BRJHUQSY.js → chunk-YALGASEU.js} +1548 -1452
- package/dist/chunk-YALGASEU.js.map +1 -0
- package/dist/chunk-YIYQ2ZNT.js +286 -0
- package/dist/chunk-YIYQ2ZNT.js.map +1 -0
- package/dist/{chunk-DXPYFVKG.js → chunk-YN5SHIXQ.js} +6 -6
- package/dist/chunk-YN5SHIXQ.js.map +1 -0
- package/dist/chunk-Z52RA3NC.js +137 -0
- package/dist/chunk-Z52RA3NC.js.map +1 -0
- package/dist/{chunk-EXBMF5X7.js → chunk-Z6MFJV5Z.js} +151 -19
- package/dist/chunk-Z6MFJV5Z.js.map +1 -0
- package/dist/chunk-ZABPQJ3M.js +83 -0
- package/dist/chunk-ZABPQJ3M.js.map +1 -0
- package/dist/{chunk-LPRVHM7P.js → chunk-ZMHYXMO6.js} +1655 -114
- package/dist/chunk-ZMHYXMO6.js.map +1 -0
- package/dist/{chunk-3IMLRUZE.js → chunk-ZXTAQYNA.js} +6 -2
- package/dist/{cli-WA65NP4Y.js → cli-4NNBEQYH.js} +177 -177
- package/dist/cli-4NNBEQYH.js.map +1 -0
- package/dist/config-2VSXWWHK.js +21 -0
- package/dist/doctor-JJPNIBYH.js +20 -0
- package/dist/doctor-JJPNIBYH.js.map +1 -0
- package/dist/ethersCompat-Df4a6QIZ-3YZIAXDK.js +18 -0
- package/dist/ethersCompat-Df4a6QIZ-3YZIAXDK.js.map +1 -0
- package/dist/index.js +1 -1
- package/dist/inspect-JGYJWFDP.js +96 -0
- package/dist/inspect-JGYJWFDP.js.map +1 -0
- package/dist/install-ZQRMSRGW.js +378 -0
- package/dist/install-ZQRMSRGW.js.map +1 -0
- package/dist/lookup-WYVTOMVY.js +113 -0
- package/dist/lookup-WYVTOMVY.js.map +1 -0
- package/dist/{mine.wasm-GQECMSGN.js → mine.wasm-6PIT3DK6.js} +2 -2
- package/dist/outcome-HKKT6QIA.js +66 -0
- package/dist/outcome-HKKT6QIA.js.map +1 -0
- package/dist/publish-D76B3MBK.js +1480 -0
- package/dist/publish-D76B3MBK.js.map +1 -0
- package/dist/{secp256k1-BEZS642W.js → secp256k1-N3ZHU7LB.js} +5 -4
- package/dist/secp256k1-N3ZHU7LB.js.map +1 -0
- package/dist/usdc-JIAJW4SV.js +22 -0
- package/dist/usdc-JIAJW4SV.js.map +1 -0
- package/dist/viemAdapter-By13KInL-ZZE6UV4Y.js +14 -0
- package/dist/viemAdapter-By13KInL-ZZE6UV4Y.js.map +1 -0
- package/dist/{wallet-XD576HF3.js → wallet-6QKS6UHW.js} +28 -22
- package/dist/{wallet-XD576HF3.js.map → wallet-6QKS6UHW.js.map} +1 -1
- package/dist/wallet-PA54CRBL.js +30 -0
- package/dist/wallet-PA54CRBL.js.map +1 -0
- package/package.json +19 -16
- package/skills/tenjin/SKILL.md +199 -0
- package/skills/tenjin-publish/SKILL.md +96 -0
- package/skills/tenjin-search/SKILL.md +122 -0
- package/dist/chunk-BRJHUQSY.js.map +0 -1
- package/dist/chunk-CUWUHTIL.js.map +0 -1
- package/dist/chunk-DXPYFVKG.js.map +0 -1
- package/dist/chunk-EXBMF5X7.js.map +0 -1
- package/dist/chunk-EZROUI5U.js.map +0 -1
- package/dist/chunk-IPOWB3G3.js.map +0 -1
- package/dist/chunk-LPRVHM7P.js.map +0 -1
- package/dist/chunk-T4LKNY7T.js.map +0 -1
- package/dist/chunk-ZPZFPVDN.js.map +0 -1
- package/dist/cli-WA65NP4Y.js.map +0 -1
- package/dist/config-CEFTL5ZL.js.map +0 -1
- package/dist/doctor-3QBYN46N.js.map +0 -1
- package/dist/usdc-44R6XZF2.js +0 -18
- package/dist/wallet-ELBTBMXO.js +0 -20
- /package/dist/{_esm-ZH2J4QEH.js.map → _esm-C5CRWCYU.js.map} +0 -0
- /package/dist/{ccip-UCLT5VOW.js.map → _esm-FEASBWRP.js.map} +0 -0
- /package/dist/{chunk-3IMLRUZE.js.map → ccip-NQXCEK2U.js.map} +0 -0
- /package/dist/{secp256k1-BEZS642W.js.map → ccip-XR5NE5QK.js.map} +0 -0
- /package/dist/{usdc-44R6XZF2.js.map → chunk-ZXTAQYNA.js.map} +0 -0
- /package/dist/{wallet-ELBTBMXO.js.map → config-2VSXWWHK.js.map} +0 -0
- /package/dist/{mine.wasm-GQECMSGN.js.map → mine.wasm-6PIT3DK6.js.map} +0 -0
|
@@ -3,29 +3,53 @@ import {
|
|
|
3
3
|
CliError,
|
|
4
4
|
configPath,
|
|
5
5
|
external_exports
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-OYMYCW7J.js";
|
|
7
7
|
|
|
8
8
|
// src/lib/config.ts
|
|
9
9
|
import { readFile } from "fs/promises";
|
|
10
10
|
var atomicString = external_exports.string().regex(/^\d+$/, "expected an atomic USDC integer string");
|
|
11
|
+
var PublishModeSchema = external_exports.enum(["review", "auto", "full-auto"]);
|
|
12
|
+
function parsePublishModeFlag(value, flagName) {
|
|
13
|
+
const parsed = PublishModeSchema.safeParse(value);
|
|
14
|
+
if (parsed.success) return parsed.data;
|
|
15
|
+
throw new CliError("USAGE", `Invalid ${flagName} ${JSON.stringify(value)}`, {
|
|
16
|
+
fix: 'Use "review", "auto", or "full-auto".'
|
|
17
|
+
});
|
|
18
|
+
}
|
|
19
|
+
var PublishConfigSchema = external_exports.object({
|
|
20
|
+
mode: PublishModeSchema,
|
|
21
|
+
defaultPrice: atomicString
|
|
22
|
+
});
|
|
11
23
|
var ConfigSchema = external_exports.object({
|
|
12
24
|
maxAutoSpend: atomicString,
|
|
13
25
|
sessionBudget: atomicString,
|
|
14
26
|
confirm: external_exports.union([external_exports.literal("always"), external_exports.string().regex(/^above:\d+$/)]),
|
|
15
27
|
allowlistCreators: external_exports.array(external_exports.string()),
|
|
16
28
|
baseUrl: external_exports.url(),
|
|
17
|
-
rpcUrl: external_exports.url()
|
|
29
|
+
rpcUrl: external_exports.url(),
|
|
30
|
+
/**
|
|
31
|
+
* Evaluation-cohort opt-in (spec 09 §3): when true, lookup sends
|
|
32
|
+
* X-Tenjin-Eval-Cohort: 1 and the server stores the generalized question for
|
|
33
|
+
* 90 days. Off by default; no query text is retained server-side without it.
|
|
34
|
+
*/
|
|
35
|
+
evalCohort: external_exports.boolean(),
|
|
36
|
+
publish: PublishConfigSchema
|
|
18
37
|
});
|
|
19
|
-
var RawConfigSchema = ConfigSchema.partial();
|
|
38
|
+
var RawConfigSchema = ConfigSchema.partial().extend({ publish: PublishConfigSchema.partial().passthrough().optional() }).passthrough();
|
|
20
39
|
var CONFIG_DEFAULTS = {
|
|
21
40
|
maxAutoSpend: "0",
|
|
22
41
|
sessionBudget: "0",
|
|
23
42
|
confirm: "always",
|
|
24
43
|
allowlistCreators: [],
|
|
25
44
|
baseUrl: "https://tenjin.blog",
|
|
26
|
-
rpcUrl: "https://mainnet.base.org"
|
|
45
|
+
rpcUrl: "https://mainnet.base.org",
|
|
46
|
+
evalCohort: false,
|
|
47
|
+
publish: { mode: "auto", defaultPrice: "100000" }
|
|
27
48
|
};
|
|
28
|
-
var CONFIG_KEYS = Object.keys(CONFIG_DEFAULTS)
|
|
49
|
+
var CONFIG_KEYS = Object.keys(CONFIG_DEFAULTS).filter(
|
|
50
|
+
(key) => key !== "publish"
|
|
51
|
+
);
|
|
52
|
+
var PUBLISH_CONFIG_KEYS = ["publish.mode", "publish.defaultPrice"];
|
|
29
53
|
async function loadRawConfig(dir) {
|
|
30
54
|
const path = configPath(dir);
|
|
31
55
|
let raw;
|
|
@@ -57,15 +81,57 @@ async function loadRawConfig(dir) {
|
|
|
57
81
|
return parsed.data;
|
|
58
82
|
}
|
|
59
83
|
function resolveSettings(input) {
|
|
60
|
-
const { config, flags, env } = input;
|
|
84
|
+
const { config, flags, env, project } = input;
|
|
61
85
|
return {
|
|
62
86
|
maxAutoSpend: fileOrDefault("maxAutoSpend", config),
|
|
63
87
|
sessionBudget: fileOrDefault("sessionBudget", config),
|
|
64
88
|
confirm: fileOrDefault("confirm", config),
|
|
65
89
|
allowlistCreators: fileOrDefault("allowlistCreators", config),
|
|
66
90
|
baseUrl: resolveBaseUrl(config, flags, env),
|
|
67
|
-
rpcUrl: fileOrDefault("rpcUrl", config)
|
|
91
|
+
rpcUrl: fileOrDefault("rpcUrl", config),
|
|
92
|
+
evalCohort: fileOrDefault("evalCohort", config),
|
|
93
|
+
publishMode: resolvePublishMode({ config, project, env }),
|
|
94
|
+
publishDefaultPrice: resolvePublishDefaultPrice({ config, project })
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
var FULL_AUTO_DOWNGRADE_WARNING = 'Ignoring publish.mode "full-auto" from a committed .tenjin.json (cloning a repo must not enable auto-publish); using "auto". Add .tenjin.json to .gitignore to opt in.';
|
|
98
|
+
function coercePublishMode(raw) {
|
|
99
|
+
if (raw === void 0 || raw.length === 0) return void 0;
|
|
100
|
+
const parsed = PublishModeSchema.safeParse(raw);
|
|
101
|
+
return parsed.success ? parsed.data : void 0;
|
|
102
|
+
}
|
|
103
|
+
function resolvePublishMode(input) {
|
|
104
|
+
const { config, project, env, flag } = input;
|
|
105
|
+
let winner = { value: CONFIG_DEFAULTS.publish.mode, source: "default" };
|
|
106
|
+
const fromFile = config.publish?.mode;
|
|
107
|
+
if (fromFile !== void 0) winner = { value: fromFile, source: "file" };
|
|
108
|
+
if (project !== void 0 && project.publish?.mode !== void 0) {
|
|
109
|
+
const fromProject = project.publish.mode;
|
|
110
|
+
if (fromProject === "full-auto" && !project.gitignored) {
|
|
111
|
+
winner = { value: "auto", source: "project", downgradedWarning: FULL_AUTO_DOWNGRADE_WARNING };
|
|
112
|
+
} else {
|
|
113
|
+
winner = { value: fromProject, source: "project" };
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
const fromEnv = coercePublishMode(env.TENJIN_PUBLISH_MODE);
|
|
117
|
+
if (fromEnv !== void 0) winner = { value: fromEnv, source: "env" };
|
|
118
|
+
const fromFlag = coercePublishMode(flag);
|
|
119
|
+
if (fromFlag !== void 0) winner = { value: fromFlag, source: "flag" };
|
|
120
|
+
return winner;
|
|
121
|
+
}
|
|
122
|
+
function resolvePublishDefaultPrice(input) {
|
|
123
|
+
const { config, project } = input;
|
|
124
|
+
let result = {
|
|
125
|
+
value: CONFIG_DEFAULTS.publish.defaultPrice,
|
|
126
|
+
source: "default"
|
|
68
127
|
};
|
|
128
|
+
if (config.publish?.defaultPrice !== void 0) {
|
|
129
|
+
result = { value: config.publish.defaultPrice, source: "file" };
|
|
130
|
+
}
|
|
131
|
+
if (project?.publish?.defaultPrice !== void 0) {
|
|
132
|
+
result = { value: project.publish.defaultPrice, source: "project" };
|
|
133
|
+
}
|
|
134
|
+
return result;
|
|
69
135
|
}
|
|
70
136
|
function fileOrDefault(key, config) {
|
|
71
137
|
const fromFile = config[key];
|
|
@@ -123,13 +189,23 @@ function atomicToUsd(atomic) {
|
|
|
123
189
|
function toMoney(atomic) {
|
|
124
190
|
return { atomic, usd: atomicToUsd(atomic) };
|
|
125
191
|
}
|
|
192
|
+
function formatUsdDisplay(atomic) {
|
|
193
|
+
const [whole, frac = ""] = atomicToUsd(atomic).split(".");
|
|
194
|
+
return `${whole}.${frac.padEnd(2, "0")}`;
|
|
195
|
+
}
|
|
126
196
|
|
|
127
197
|
export {
|
|
198
|
+
PublishModeSchema,
|
|
199
|
+
parsePublishModeFlag,
|
|
128
200
|
RawConfigSchema,
|
|
129
201
|
CONFIG_KEYS,
|
|
202
|
+
PUBLISH_CONFIG_KEYS,
|
|
130
203
|
loadRawConfig,
|
|
131
204
|
resolveSettings,
|
|
205
|
+
resolvePublishMode,
|
|
206
|
+
resolvePublishDefaultPrice,
|
|
132
207
|
parseUsdToAtomic,
|
|
133
|
-
toMoney
|
|
208
|
+
toMoney,
|
|
209
|
+
formatUsdDisplay
|
|
134
210
|
};
|
|
135
|
-
//# sourceMappingURL=chunk-
|
|
211
|
+
//# sourceMappingURL=chunk-IYLHQMT5.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/lib/config.ts","../src/lib/money.ts"],"sourcesContent":["import { readFile } from 'node:fs/promises';\nimport { z } from 'zod';\nimport { CliError } from './errors';\nimport { configPath } from './paths';\nimport { writeFileAtomic } from './atomic-json';\n\n/** A non-negative integer string in USDC atomic units (6-decimal base). */\nconst atomicString = z.string().regex(/^\\d+$/, 'expected an atomic USDC integer string');\n\n/** The publish consent mode (B3, D38). `full-auto` is loosening-gated, below. */\nexport const PublishModeSchema = z.enum(['review', 'auto', 'full-auto']);\nexport type PublishMode = z.infer<typeof PublishModeSchema>;\n\n/**\n * Validate a publish-mode value at a command edge (`--mode`, `--publish-mode`):\n * an unrecognized value is USAGE (exit 2), never silently dropped. `flagName` is\n * woven into the message so the failing flag is named.\n */\nexport function parsePublishModeFlag(value: string, flagName: string): PublishMode {\n const parsed = PublishModeSchema.safeParse(value);\n if (parsed.success) return parsed.data;\n throw new CliError('USAGE', `Invalid ${flagName} ${JSON.stringify(value)}`, {\n fix: 'Use \"review\", \"auto\", or \"full-auto\".',\n });\n}\n\n/**\n * The publish block (B3): `mode` governs the confirm cascade a `publish` runs,\n * `defaultPrice` is the atomic USDC price a card is published at when no\n * per-publish price is given. Stored atomic like the spend keys.\n */\nconst PublishConfigSchema = z.object({\n mode: PublishModeSchema,\n defaultPrice: atomicString,\n});\n\n/**\n * The persisted config shape. Spend keys are stored atomic (accepted as decimal\n * USD at the command edge, see lib/money); `confirm` is the stored form\n * \"always\" | \"above:<atomic>\". These are client-enforced guardrails, not a\n * security boundary — any process that runs the CLI can also edit this file.\n */\nexport const ConfigSchema = z.object({\n maxAutoSpend: atomicString,\n sessionBudget: atomicString,\n confirm: z.union([z.literal('always'), z.string().regex(/^above:\\d+$/)]),\n allowlistCreators: z.array(z.string()),\n baseUrl: z.url(),\n rpcUrl: z.url(),\n /**\n * Evaluation-cohort opt-in (spec 09 §3): when true, lookup sends\n * X-Tenjin-Eval-Cohort: 1 and the server stores the generalized question for\n * 90 days. Off by default; no query text is retained server-side without it.\n */\n evalCohort: z.boolean(),\n publish: PublishConfigSchema,\n});\nexport type Config = z.infer<typeof ConfigSchema>;\n\n/**\n * Values as they may appear in config.json — every known key optional; absent =\n * default. `.passthrough()` PRESERVES unknown keys through load + persist: without\n * it an older binary's `config set` would strip (and re-serialize away) any newer\n * block a later CLI wrote, e.g. B3's `publish.*`. Known keys are still validated;\n * unknown keys ride along untouched.\n */\nexport const RawConfigSchema = ConfigSchema.partial()\n // The publish block is itself partial + passthrough: `config set publish.mode`\n // writes only the one subkey, and a subkey a newer CLI adds (e.g. publish.*\n // beyond mode/defaultPrice) survives an older binary's set, same reason the\n // outer object passes unknown keys through.\n .extend({ publish: PublishConfigSchema.partial().passthrough().optional() })\n .passthrough();\nexport type PartialConfig = z.infer<typeof RawConfigSchema>;\n\nexport const CONFIG_DEFAULTS: Config = {\n maxAutoSpend: '0',\n sessionBudget: '0',\n confirm: 'always',\n allowlistCreators: [],\n baseUrl: 'https://tenjin.blog',\n rpcUrl: 'https://mainnet.base.org',\n evalCohort: false,\n publish: { mode: 'auto', defaultPrice: '100000' },\n};\n\n/**\n * Scalar keys `config get/set/list` render one line each. `publish` is excluded:\n * it is a nested block addressed by the dotted `publish.mode`/`publish.defaultPrice`\n * keys (see PUBLISH_CONFIG_KEYS), so it is never rendered as a bare scalar.\n */\nexport type ScalarConfigKey = Exclude<keyof Config, 'publish'>;\nexport const CONFIG_KEYS = (Object.keys(CONFIG_DEFAULTS) as Array<keyof Config>).filter(\n (key): key is ScalarConfigKey => key !== 'publish',\n);\n\n/** The dotted keys `config get/set` accept for the nested publish block. */\nexport const PUBLISH_CONFIG_KEYS = ['publish.mode', 'publish.defaultPrice'] as const;\nexport type PublishConfigKey = (typeof PUBLISH_CONFIG_KEYS)[number];\n\n/**\n * Read and validate config.json WITHOUT applying defaults, so provenance can\n * distinguish \"present in file\" from \"absent\". Missing file is fine (returns\n * {}); malformed JSON or a failed schema is CONFIG_INVALID with a fix.\n */\nexport async function loadRawConfig(dir: string): Promise<PartialConfig> {\n const path = configPath(dir);\n let raw: string;\n try {\n raw = await readFile(path, 'utf8');\n } catch (err) {\n if (isNotFound(err)) return {};\n throw new CliError('CONFIG_INVALID', `Could not read config at ${path}`, {\n fix: `Check file permissions on ${path}.`,\n cause: err,\n });\n }\n let json: unknown;\n try {\n json = JSON.parse(raw);\n } catch (err) {\n throw new CliError('CONFIG_INVALID', `Config at ${path} is not valid JSON`, {\n fix: `Fix the JSON syntax in ${path}, or delete it to restore defaults.`,\n cause: err,\n });\n }\n const parsed = RawConfigSchema.safeParse(json);\n if (!parsed.success) {\n throw new CliError('CONFIG_INVALID', `Config at ${path} is invalid`, {\n fix: `Correct the reported keys in ${path}, or delete it to restore defaults.`,\n details: parsed.error.issues,\n });\n }\n return parsed.data;\n}\n\n/** File values merged over defaults — the effective persisted config. The nested\n * publish block is merged per-subkey so a file that sets only publish.mode keeps\n * the default defaultPrice (a shallow spread would drop it). */\nexport async function loadConfig(dir: string): Promise<Config> {\n const raw = await loadRawConfig(dir);\n return {\n ...CONFIG_DEFAULTS,\n ...raw,\n publish: {\n mode: raw.publish?.mode ?? CONFIG_DEFAULTS.publish.mode,\n defaultPrice: raw.publish?.defaultPrice ?? CONFIG_DEFAULTS.publish.defaultPrice,\n },\n };\n}\n\nexport type Provenance = 'default' | 'file' | 'project' | 'env' | 'flag';\n\nexport interface ResolvedSetting<T> {\n value: T;\n source: Provenance;\n}\n\n/**\n * The per-project `.tenjin.json` layer (B3, D38): publish overrides discovered by\n * walking up from cwd, plus whether that file is gitignored. `gitignored` gates\n * `full-auto` — a committed file requesting it is downgraded (loosening gate).\n */\nexport interface ProjectPublishLayer {\n publish?: { mode?: PublishMode; defaultPrice?: string };\n gitignored: boolean;\n}\n\n/** publish.mode resolution: value, source, and the downgrade warning (if any). */\nexport interface PublishModeResolution {\n value: PublishMode;\n source: Provenance;\n /** Set when a committed `.tenjin.json`'s `full-auto` was downgraded to `auto`. */\n downgradedWarning?: string;\n}\n\n/** Effective value + where it came from, per key. What `config` (bare) renders. */\nexport interface EffectiveSettings {\n maxAutoSpend: ResolvedSetting<string>;\n sessionBudget: ResolvedSetting<string>;\n confirm: ResolvedSetting<string>;\n allowlistCreators: ResolvedSetting<string[]>;\n baseUrl: ResolvedSetting<string>;\n rpcUrl: ResolvedSetting<string>;\n evalCohort: ResolvedSetting<boolean>;\n publishMode: PublishModeResolution;\n publishDefaultPrice: ResolvedSetting<string>;\n}\n\n/** CLI flags that participate in settings precedence (`--base-url`). */\nexport interface SettingsFlags {\n baseUrl?: string;\n}\n\nexport interface ResolveSettingsInput {\n /** Raw file values (present keys only) — from loadRawConfig, not loadConfig. */\n config: PartialConfig;\n flags: SettingsFlags;\n env: NodeJS.ProcessEnv;\n /** The nearest `.tenjin.json` layer, when one was found (see publish-settings). */\n project?: ProjectPublishLayer;\n}\n\n/**\n * Apply precedence flag > env > file > default per key, returning each effective\n * value with its source. In B1 only baseUrl has flag/env overrides\n * (`--base-url`, TENJIN_BASE_URL); the rest resolve file-or-default. B3 adds the\n * publish keys, which additionally fold in the per-project `.tenjin.json` layer.\n */\nexport function resolveSettings(input: ResolveSettingsInput): EffectiveSettings {\n const { config, flags, env, project } = input;\n return {\n maxAutoSpend: fileOrDefault('maxAutoSpend', config),\n sessionBudget: fileOrDefault('sessionBudget', config),\n confirm: fileOrDefault('confirm', config),\n allowlistCreators: fileOrDefault('allowlistCreators', config),\n baseUrl: resolveBaseUrl(config, flags, env),\n rpcUrl: fileOrDefault('rpcUrl', config),\n evalCohort: fileOrDefault('evalCohort', config),\n publishMode: resolvePublishMode({ config, project, env }),\n publishDefaultPrice: resolvePublishDefaultPrice({ config, project }),\n };\n}\n\n/**\n * The loosening gate (D38): a committed (not-gitignored) `.tenjin.json` requesting\n * `full-auto` is downgraded to `auto`, never silently honored — cloning a repo\n * must not enable auto-publish. `full-auto` from global config / env / flag (all\n * inherently local, not cloned) is always honored.\n */\nconst FULL_AUTO_DOWNGRADE_WARNING =\n 'Ignoring publish.mode \"full-auto\" from a committed .tenjin.json (cloning a repo must not enable auto-publish); using \"auto\". Add .tenjin.json to .gitignore to opt in.';\n\nfunction coercePublishMode(raw: string | undefined): PublishMode | undefined {\n if (raw === undefined || raw.length === 0) return undefined;\n const parsed = PublishModeSchema.safeParse(raw);\n return parsed.success ? parsed.data : undefined;\n}\n\n/**\n * Resolve publish.mode through global file < project `.tenjin.json` < env\n * (TENJIN_PUBLISH_MODE) < flag (`--mode`). Total: an invalid env/flag value is\n * ignored (validation lives at the command edge, like baseUrl). The project\n * layer's `full-auto` is gated on that file being gitignored.\n */\nexport function resolvePublishMode(input: {\n config: PartialConfig;\n project?: ProjectPublishLayer;\n env: NodeJS.ProcessEnv;\n flag?: string;\n}): PublishModeResolution {\n const { config, project, env, flag } = input;\n let winner: PublishModeResolution = { value: CONFIG_DEFAULTS.publish.mode, source: 'default' };\n\n const fromFile = config.publish?.mode;\n if (fromFile !== undefined) winner = { value: fromFile, source: 'file' };\n\n if (project !== undefined && project.publish?.mode !== undefined) {\n const fromProject = project.publish.mode;\n if (fromProject === 'full-auto' && !project.gitignored) {\n winner = { value: 'auto', source: 'project', downgradedWarning: FULL_AUTO_DOWNGRADE_WARNING };\n } else {\n winner = { value: fromProject, source: 'project' };\n }\n }\n\n const fromEnv = coercePublishMode(env.TENJIN_PUBLISH_MODE);\n if (fromEnv !== undefined) winner = { value: fromEnv, source: 'env' };\n\n const fromFlag = coercePublishMode(flag);\n if (fromFlag !== undefined) winner = { value: fromFlag, source: 'flag' };\n\n return winner;\n}\n\n/** Resolve publish.defaultPrice (atomic) through global file < project < default. */\nexport function resolvePublishDefaultPrice(input: {\n config: PartialConfig;\n project?: ProjectPublishLayer;\n}): ResolvedSetting<string> {\n const { config, project } = input;\n let result: ResolvedSetting<string> = {\n value: CONFIG_DEFAULTS.publish.defaultPrice,\n source: 'default',\n };\n if (config.publish?.defaultPrice !== undefined) {\n result = { value: config.publish.defaultPrice, source: 'file' };\n }\n if (project?.publish?.defaultPrice !== undefined) {\n result = { value: project.publish.defaultPrice, source: 'project' };\n }\n return result;\n}\n\n/** Persist a full, validated config via the atomic writer (0700 dir, 0644 file). */\nexport async function writeConfig(dir: string, config: Config): Promise<void> {\n const validated = ConfigSchema.parse(config);\n await writeFileAtomic(configPath(dir), `${JSON.stringify(validated, null, 2)}\\n`, {\n mode: 0o644,\n dirMode: 0o700,\n });\n}\n\nfunction fileOrDefault<K extends keyof Config>(\n key: K,\n config: PartialConfig,\n): ResolvedSetting<Config[K]> {\n const fromFile = config[key];\n // PartialConfig[K] is Config[K] | undefined; narrowing an indexed access of a\n // type parameter doesn't refine K, so assert the excluded-undefined type.\n if (fromFile !== undefined) return { value: fromFile as Config[K], source: 'file' };\n return { value: CONFIG_DEFAULTS[key], source: 'default' };\n}\n\nfunction resolveBaseUrl(\n config: PartialConfig,\n flags: SettingsFlags,\n env: NodeJS.ProcessEnv,\n): ResolvedSetting<string> {\n if (flags.baseUrl !== undefined && flags.baseUrl.length > 0) {\n return { value: flags.baseUrl, source: 'flag' };\n }\n const fromEnv = env.TENJIN_BASE_URL;\n if (fromEnv !== undefined && fromEnv.length > 0) {\n return { value: fromEnv, source: 'env' };\n }\n if (config.baseUrl !== undefined) return { value: config.baseUrl, source: 'file' };\n return { value: CONFIG_DEFAULTS.baseUrl, source: 'default' };\n}\n\nfunction isNotFound(err: unknown): boolean {\n return (\n typeof err === 'object' &&\n err !== null &&\n 'code' in err &&\n (err as { code?: unknown }).code === 'ENOENT'\n );\n}\n","import { CliError } from './errors';\nimport type { Money } from '../schemas';\n\n/** USDC is a 6-decimal token; one dollar is 1_000_000 atomic units. */\nconst USDC_DECIMALS = 6;\n\n/**\n * Decimal USD at the CLI edge -> atomic USDC string (O1). Accepts \"0\", \"0.25\",\n * \"5\"; rejects negatives, non-numeric input, and more than 6 decimal places as\n * USAGE so a fat-fingered amount fails loudly instead of truncating money.\n * String math throughout — a float would lose precision at the 6th decimal.\n */\nexport function parseUsdToAtomic(input: string): string {\n const trimmed = input.trim();\n if (!/^\\d+(\\.\\d+)?$/.test(trimmed)) {\n throw new CliError('USAGE', `Invalid USD amount: ${JSON.stringify(input)}`, {\n fix: 'Pass a non-negative decimal like 0.25 or 5.',\n });\n }\n const [whole, frac = ''] = trimmed.split('.');\n if (frac.length > USDC_DECIMALS) {\n throw new CliError(\n 'USAGE',\n `USD amount ${JSON.stringify(input)} has more than 6 decimal places`,\n {\n fix: 'USDC supports at most 6 decimal places (micro-dollars).',\n },\n );\n }\n const atomic = BigInt(`${whole}${frac.padEnd(USDC_DECIMALS, '0')}`);\n return atomic.toString();\n}\n\n/**\n * Atomic USDC string -> decimal USD string, trailing zeros trimmed (\"250000\" ->\n * \"0.25\", \"5000000\" -> \"5\", \"0\" -> \"0\"). Throws INTERNAL on a malformed atomic\n * value: atomic strings come from validated config or on-chain reads, so a bad\n * one is a bug, not user input.\n */\nexport function atomicToUsd(atomic: string): string {\n const trimmed = atomic.trim();\n if (!/^\\d+$/.test(trimmed)) {\n throw new CliError('INTERNAL', `Malformed atomic amount: ${JSON.stringify(atomic)}`);\n }\n const value = BigInt(trimmed);\n const base = 10n ** BigInt(USDC_DECIMALS);\n const whole = value / base;\n const frac = (value % base).toString().padStart(USDC_DECIMALS, '0').replace(/0+$/, '');\n return frac.length > 0 ? `${whole}.${frac}` : whole.toString();\n}\n\n/** Dual-form money object for machine output. */\nexport function toMoney(atomic: string): Money {\n return { atomic, usd: atomicToUsd(atomic) };\n}\n\n/**\n * Canonical USD for human COPY (a price a person reads): always at least two\n * decimals (\"0.10\", \"5.00\"), keeping any finer precision below a cent\n * (\"0.000001\"). Distinct from `atomicToUsd`, which trims to the shortest exact\n * form for machine output; use this only where a dollar amount is shown to a human.\n */\nexport function formatUsdDisplay(atomic: string): string {\n const [whole, frac = ''] = atomicToUsd(atomic).split('.');\n return `${whole}.${frac.padEnd(2, '0')}`;\n}\n"],"mappings":"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","names":[]}
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import { createRequire as __tenjinCreateRequire } from 'node:module'; const require = __tenjinCreateRequire(import.meta.url);
|
|
2
|
+
import {
|
|
3
|
+
withFileLock
|
|
4
|
+
} from "./chunk-YBMMV4Y4.js";
|
|
5
|
+
import {
|
|
6
|
+
writeFileAtomic
|
|
7
|
+
} from "./chunk-MUBUQVC3.js";
|
|
8
|
+
import {
|
|
9
|
+
external_exports
|
|
10
|
+
} from "./chunk-OYMYCW7J.js";
|
|
11
|
+
|
|
12
|
+
// src/lib/lookup-store.ts
|
|
13
|
+
import { mkdir, readFile } from "fs/promises";
|
|
14
|
+
import { join } from "path";
|
|
15
|
+
var MAX_ENTRIES = 50;
|
|
16
|
+
var StoredCandidateSchema = external_exports.object({
|
|
17
|
+
resourceId: external_exports.string(),
|
|
18
|
+
url: external_exports.string(),
|
|
19
|
+
title: external_exports.string(),
|
|
20
|
+
price: external_exports.string()
|
|
21
|
+
});
|
|
22
|
+
var StoredLookupSchema = external_exports.object({
|
|
23
|
+
lookupId: external_exports.string(),
|
|
24
|
+
at: external_exports.string(),
|
|
25
|
+
question: external_exports.string(),
|
|
26
|
+
decision: external_exports.string(),
|
|
27
|
+
candidates: external_exports.array(StoredCandidateSchema)
|
|
28
|
+
});
|
|
29
|
+
var StoreSchema = external_exports.object({
|
|
30
|
+
schemaVersion: external_exports.literal(1),
|
|
31
|
+
lookups: external_exports.array(StoredLookupSchema)
|
|
32
|
+
});
|
|
33
|
+
function storePath(dataDir) {
|
|
34
|
+
return join(dataDir, "lookups.json");
|
|
35
|
+
}
|
|
36
|
+
async function loadLookups(dataDir) {
|
|
37
|
+
let raw;
|
|
38
|
+
try {
|
|
39
|
+
raw = await readFile(storePath(dataDir), "utf8");
|
|
40
|
+
} catch {
|
|
41
|
+
return [];
|
|
42
|
+
}
|
|
43
|
+
let json;
|
|
44
|
+
try {
|
|
45
|
+
json = JSON.parse(raw);
|
|
46
|
+
} catch {
|
|
47
|
+
return [];
|
|
48
|
+
}
|
|
49
|
+
const parsed = StoreSchema.safeParse(json);
|
|
50
|
+
return parsed.success ? parsed.data.lookups : [];
|
|
51
|
+
}
|
|
52
|
+
async function recordLookup(dataDir, entry) {
|
|
53
|
+
await mkdir(dataDir, { recursive: true, mode: 448 });
|
|
54
|
+
const lockPath = `${storePath(dataDir)}.lock`;
|
|
55
|
+
await withFileLock(lockPath, async () => {
|
|
56
|
+
const existing = await loadLookups(dataDir);
|
|
57
|
+
const lookups = [entry, ...existing.filter((l) => l.lookupId !== entry.lookupId)].slice(
|
|
58
|
+
0,
|
|
59
|
+
MAX_ENTRIES
|
|
60
|
+
);
|
|
61
|
+
await writeFileAtomic(
|
|
62
|
+
storePath(dataDir),
|
|
63
|
+
`${JSON.stringify({ schemaVersion: 1, lookups }, null, 2)}
|
|
64
|
+
`,
|
|
65
|
+
{ mode: 420, dirMode: 448 }
|
|
66
|
+
);
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
async function latestLookup(dataDir) {
|
|
70
|
+
const lookups = await loadLookups(dataDir);
|
|
71
|
+
return lookups[0] ?? null;
|
|
72
|
+
}
|
|
73
|
+
async function findStoredCandidate(dataDir, resourceId) {
|
|
74
|
+
for (const lookup of await loadLookups(dataDir)) {
|
|
75
|
+
const hit = lookup.candidates.find((c) => c.resourceId === resourceId);
|
|
76
|
+
if (hit) return hit;
|
|
77
|
+
}
|
|
78
|
+
return null;
|
|
79
|
+
}
|
|
80
|
+
async function findLookupForResource(dataDir, match) {
|
|
81
|
+
for (const lookup of await loadLookups(dataDir)) {
|
|
82
|
+
const hit = lookup.candidates.some(
|
|
83
|
+
(c) => match.resourceId !== void 0 && c.resourceId === match.resourceId || match.url !== void 0 && c.url === match.url
|
|
84
|
+
);
|
|
85
|
+
if (hit) return lookup.lookupId;
|
|
86
|
+
}
|
|
87
|
+
return null;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
export {
|
|
91
|
+
recordLookup,
|
|
92
|
+
latestLookup,
|
|
93
|
+
findStoredCandidate,
|
|
94
|
+
findLookupForResource
|
|
95
|
+
};
|
|
96
|
+
//# sourceMappingURL=chunk-JPHG2JW3.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/lib/lookup-store.ts"],"sourcesContent":["import { mkdir, readFile } from 'node:fs/promises';\nimport { join } from 'node:path';\nimport { z } from 'zod';\nimport { writeFileAtomic } from './atomic-json';\nimport { withFileLock } from './lock';\n\n/**\n * A small local ledger of recent lookups so `outcome --last` can target the most\n * recent one and `buy <resourceId>` can resolve the payable read URL a candidate\n * carried (the read route is keyed by handle/slug, not id, so an id alone can't\n * build the URL). Bounded and best-effort: a corrupt file reads as empty rather\n * than blocking a command. NOT an entitlement record, that is the library receipt.\n */\n\nconst MAX_ENTRIES = 50;\n\nconst StoredCandidateSchema = z.object({\n resourceId: z.string(),\n url: z.string(),\n title: z.string(),\n price: z.string(),\n});\nexport type StoredCandidate = z.infer<typeof StoredCandidateSchema>;\n\nconst StoredLookupSchema = z.object({\n lookupId: z.string(),\n at: z.string(),\n question: z.string(),\n decision: z.string(),\n candidates: z.array(StoredCandidateSchema),\n});\nexport type StoredLookup = z.infer<typeof StoredLookupSchema>;\n\nconst StoreSchema = z.object({\n schemaVersion: z.literal(1),\n lookups: z.array(StoredLookupSchema),\n});\n\nfunction storePath(dataDir: string): string {\n return join(dataDir, 'lookups.json');\n}\n\nexport async function loadLookups(dataDir: string): Promise<StoredLookup[]> {\n let raw: string;\n try {\n raw = await readFile(storePath(dataDir), 'utf8');\n } catch {\n return [];\n }\n let json: unknown;\n try {\n json = JSON.parse(raw);\n } catch {\n return [];\n }\n const parsed = StoreSchema.safeParse(json);\n return parsed.success ? parsed.data.lookups : [];\n}\n\n/** Prepend a lookup (newest first), cap to MAX_ENTRIES, persist under a lock so\n * concurrent lookups don't drop each other's entry. */\nexport async function recordLookup(dataDir: string, entry: StoredLookup): Promise<void> {\n await mkdir(dataDir, { recursive: true, mode: 0o700 });\n const lockPath = `${storePath(dataDir)}.lock`;\n await withFileLock(lockPath, async () => {\n const existing = await loadLookups(dataDir);\n const lookups = [entry, ...existing.filter((l) => l.lookupId !== entry.lookupId)].slice(\n 0,\n MAX_ENTRIES,\n );\n await writeFileAtomic(\n storePath(dataDir),\n `${JSON.stringify({ schemaVersion: 1, lookups }, null, 2)}\\n`,\n { mode: 0o644, dirMode: 0o700 },\n );\n });\n}\n\nexport async function latestLookup(dataDir: string): Promise<StoredLookup | null> {\n const lookups = await loadLookups(dataDir);\n return lookups[0] ?? null;\n}\n\n/** The stored candidate for a resourceId across recent lookups (newest first). */\nexport async function findStoredCandidate(\n dataDir: string,\n resourceId: string,\n): Promise<StoredCandidate | null> {\n for (const lookup of await loadLookups(dataDir)) {\n const hit = lookup.candidates.find((c) => c.resourceId === resourceId);\n if (hit) return hit;\n }\n return null;\n}\n\n/** The most recent lookupId that surfaced this resource (by id or url), for\n * purchase attribution (`X-Tenjin-Lookup-Id`). Null when no local lookup did. */\nexport async function findLookupForResource(\n dataDir: string,\n match: { resourceId?: string; url?: string },\n): Promise<string | null> {\n for (const lookup of await loadLookups(dataDir)) {\n const hit = lookup.candidates.some(\n (c) =>\n (match.resourceId !== undefined && c.resourceId === match.resourceId) ||\n (match.url !== undefined && c.url === match.url),\n );\n if (hit) return lookup.lookupId;\n }\n return null;\n}\n"],"mappings":";;;;;;;;;;;;AAAA,SAAS,OAAO,gBAAgB;AAChC,SAAS,YAAY;AAarB,IAAM,cAAc;AAEpB,IAAM,wBAAwB,iBAAE,OAAO;AAAA,EACrC,YAAY,iBAAE,OAAO;AAAA,EACrB,KAAK,iBAAE,OAAO;AAAA,EACd,OAAO,iBAAE,OAAO;AAAA,EAChB,OAAO,iBAAE,OAAO;AAClB,CAAC;AAGD,IAAM,qBAAqB,iBAAE,OAAO;AAAA,EAClC,UAAU,iBAAE,OAAO;AAAA,EACnB,IAAI,iBAAE,OAAO;AAAA,EACb,UAAU,iBAAE,OAAO;AAAA,EACnB,UAAU,iBAAE,OAAO;AAAA,EACnB,YAAY,iBAAE,MAAM,qBAAqB;AAC3C,CAAC;AAGD,IAAM,cAAc,iBAAE,OAAO;AAAA,EAC3B,eAAe,iBAAE,QAAQ,CAAC;AAAA,EAC1B,SAAS,iBAAE,MAAM,kBAAkB;AACrC,CAAC;AAED,SAAS,UAAU,SAAyB;AAC1C,SAAO,KAAK,SAAS,cAAc;AACrC;AAEA,eAAsB,YAAY,SAA0C;AAC1E,MAAI;AACJ,MAAI;AACF,UAAM,MAAM,SAAS,UAAU,OAAO,GAAG,MAAM;AAAA,EACjD,QAAQ;AACN,WAAO,CAAC;AAAA,EACV;AACA,MAAI;AACJ,MAAI;AACF,WAAO,KAAK,MAAM,GAAG;AAAA,EACvB,QAAQ;AACN,WAAO,CAAC;AAAA,EACV;AACA,QAAM,SAAS,YAAY,UAAU,IAAI;AACzC,SAAO,OAAO,UAAU,OAAO,KAAK,UAAU,CAAC;AACjD;AAIA,eAAsB,aAAa,SAAiB,OAAoC;AACtF,QAAM,MAAM,SAAS,EAAE,WAAW,MAAM,MAAM,IAAM,CAAC;AACrD,QAAM,WAAW,GAAG,UAAU,OAAO,CAAC;AACtC,QAAM,aAAa,UAAU,YAAY;AACvC,UAAM,WAAW,MAAM,YAAY,OAAO;AAC1C,UAAM,UAAU,CAAC,OAAO,GAAG,SAAS,OAAO,CAAC,MAAM,EAAE,aAAa,MAAM,QAAQ,CAAC,EAAE;AAAA,MAChF;AAAA,MACA;AAAA,IACF;AACA,UAAM;AAAA,MACJ,UAAU,OAAO;AAAA,MACjB,GAAG,KAAK,UAAU,EAAE,eAAe,GAAG,QAAQ,GAAG,MAAM,CAAC,CAAC;AAAA;AAAA,MACzD,EAAE,MAAM,KAAO,SAAS,IAAM;AAAA,IAChC;AAAA,EACF,CAAC;AACH;AAEA,eAAsB,aAAa,SAA+C;AAChF,QAAM,UAAU,MAAM,YAAY,OAAO;AACzC,SAAO,QAAQ,CAAC,KAAK;AACvB;AAGA,eAAsB,oBACpB,SACA,YACiC;AACjC,aAAW,UAAU,MAAM,YAAY,OAAO,GAAG;AAC/C,UAAM,MAAM,OAAO,WAAW,KAAK,CAAC,MAAM,EAAE,eAAe,UAAU;AACrE,QAAI,IAAK,QAAO;AAAA,EAClB;AACA,SAAO;AACT;AAIA,eAAsB,sBACpB,SACA,OACwB;AACxB,aAAW,UAAU,MAAM,YAAY,OAAO,GAAG;AAC/C,UAAM,MAAM,OAAO,WAAW;AAAA,MAC5B,CAAC,MACE,MAAM,eAAe,UAAa,EAAE,eAAe,MAAM,cACzD,MAAM,QAAQ,UAAa,EAAE,QAAQ,MAAM;AAAA,IAChD;AACA,QAAI,IAAK,QAAO,OAAO;AAAA,EACzB;AACA,SAAO;AACT;","names":[]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/lib/atomic-json.ts"],"sourcesContent":["import { chmod, link, mkdir, open, rename, rm, writeFile } from 'node:fs/promises';\nimport { randomBytes } from 'node:crypto';\nimport { basename, dirname, join } from 'node:path';\n\n/** fs modes are no-ops on Windows; the 0600/0700 custody story does not apply. */\nconst isWindows = process.platform === 'win32';\n\nexport interface AtomicWriteOptions {\n /** Mode for the written file (ignored on win32). Default 0o644. */\n mode?: number;\n /** Mode for the parent dir when this call creates it (ignored on win32). Default 0o755. */\n dirMode?: number;\n}\n\n/**\n * Write `data` to `targetPath` atomically: a uniquely-named temp file is created\n * in the SAME directory (so the rename is atomic — a cross-filesystem rename is\n * not), given the final mode at open time, then renamed over the target. A\n * reader therefore sees either the old file or the fully-written new one, never\n * a partial write.\n *\n * The temp file is born with the caller's `mode` (0o600 for a wallet key) so the\n * bytes are never written through a world-readable descriptor; the follow-up\n * chmod only makes the mode exact under an unusual umask and only ever touches\n * the temp path, so the live target still appears atomically at its final mode.\n */\nexport async function writeFileAtomic(\n targetPath: string,\n data: string | Buffer,\n opts: AtomicWriteOptions = {},\n): Promise<void> {\n const dir = dirname(targetPath);\n const fileMode = opts.mode ?? 0o644;\n const dirMode = opts.dirMode ?? 0o755;\n\n await mkdir(dir, { recursive: true, ...(isWindows ? {} : { mode: dirMode }) });\n\n const tmpPath = join(dir, `.${basename(targetPath)}.${randomBytes(6).toString('hex')}.tmp`);\n try {\n await writeFile(tmpPath, data, isWindows ? undefined : { mode: fileMode });\n if (!isWindows) await chmod(tmpPath, fileMode);\n await rename(tmpPath, targetPath);\n } catch (err) {\n await rm(tmpPath, { force: true }).catch(() => undefined);\n throw err;\n }\n}\n\n/**\n * Like {@link writeFileAtomic} but NO-CLOBBER and crash-durable: the commit fails\n * with `EEXIST` when `targetPath` already exists instead of replacing it, and the\n * new entry is fsynced before returning. This is what a wallet key needs — two\n * concurrent `create`/`import` runs must not both \"succeed\" and silently lose one\n * key; the loser gets a distinguishable EEXIST the wallet layer maps to\n * WALLET_EXISTS.\n *\n * The temp file is fsynced, then `link()` commits it — link is atomic and throws\n * EEXIST if the target already exists, so the check-then-write race is closed at\n * the filesystem, not by an earlier stat. The parent dir is then fsynced so the\n * new entry survives a crash. On win32, link semantics differ and a directory\n * cannot be fsynced, so we fall back to an exclusive `wx` open (still atomic\n * create-or-EEXIST, just not crash-durable — win32 has no 0600 custody story to\n * protect anyway).\n */\nexport async function writeFileAtomicExclusive(\n targetPath: string,\n data: string,\n opts: AtomicWriteOptions = {},\n): Promise<void> {\n const dir = dirname(targetPath);\n const fileMode = opts.mode ?? 0o644;\n const dirMode = opts.dirMode ?? 0o755;\n\n await mkdir(dir, { recursive: true, ...(isWindows ? {} : { mode: dirMode }) });\n\n if (isWindows) {\n const handle = await open(targetPath, 'wx');\n try {\n await handle.writeFile(data);\n await handle.sync();\n } finally {\n await handle.close();\n }\n return;\n }\n\n const tmpPath = join(dir, `.${basename(targetPath)}.${randomBytes(6).toString('hex')}.tmp`);\n try {\n const handle = await open(tmpPath, 'wx', fileMode);\n try {\n await handle.writeFile(data);\n await handle.chmod(fileMode); // exact mode even under an unusual umask\n await handle.sync();\n } finally {\n await handle.close();\n }\n await link(tmpPath, targetPath); // atomic; throws EEXIST when the target exists\n await fsyncDir(dir);\n } finally {\n // On success the temp is now a redundant link to the target; on EEXIST it is\n // the orphaned write. Either way remove it before returning/throwing.\n await rm(tmpPath, { force: true }).catch(() => undefined);\n }\n}\n\n/** fsync a directory so a freshly linked entry is durable. Never called on win32. */\nasync function fsyncDir(dir: string): Promise<void> {\n const handle = await open(dir, 'r');\n try {\n await handle.sync();\n } finally {\n await handle.close();\n }\n}\n"],"mappings":";;;AAAA,SAAS,OAAO,MAAM,OAAO,MAAM,QAAQ,IAAI,iBAAiB;AAChE,SAAS,mBAAmB;AAC5B,SAAS,UAAU,SAAS,YAAY;AAGxC,IAAM,YAAY,QAAQ,aAAa;AAqBvC,eAAsB,gBACpB,YACA,MACA,OAA2B,CAAC,GACb;AACf,QAAM,MAAM,QAAQ,UAAU;AAC9B,QAAM,WAAW,KAAK,QAAQ;AAC9B,QAAM,UAAU,KAAK,WAAW;AAEhC,QAAM,MAAM,KAAK,EAAE,WAAW,MAAM,GAAI,YAAY,CAAC,IAAI,EAAE,MAAM,QAAQ,EAAG,CAAC;AAE7E,QAAM,UAAU,KAAK,KAAK,IAAI,SAAS,UAAU,CAAC,IAAI,YAAY,CAAC,EAAE,SAAS,KAAK,CAAC,MAAM;AAC1F,MAAI;AACF,UAAM,UAAU,SAAS,MAAM,YAAY,SAAY,EAAE,MAAM,SAAS,CAAC;AACzE,QAAI,CAAC,UAAW,OAAM,MAAM,SAAS,QAAQ;AAC7C,UAAM,OAAO,SAAS,UAAU;AAAA,EAClC,SAAS,KAAK;AACZ,UAAM,GAAG,SAAS,EAAE,OAAO,KAAK,CAAC,EAAE,MAAM,MAAM,MAAS;AACxD,UAAM;AAAA,EACR;AACF;AAkBA,eAAsB,yBACpB,YACA,MACA,OAA2B,CAAC,GACb;AACf,QAAM,MAAM,QAAQ,UAAU;AAC9B,QAAM,WAAW,KAAK,QAAQ;AAC9B,QAAM,UAAU,KAAK,WAAW;AAEhC,QAAM,MAAM,KAAK,EAAE,WAAW,MAAM,GAAI,YAAY,CAAC,IAAI,EAAE,MAAM,QAAQ,EAAG,CAAC;AAE7E,MAAI,WAAW;AACb,UAAM,SAAS,MAAM,KAAK,YAAY,IAAI;AAC1C,QAAI;AACF,YAAM,OAAO,UAAU,IAAI;AAC3B,YAAM,OAAO,KAAK;AAAA,IACpB,UAAE;AACA,YAAM,OAAO,MAAM;AAAA,IACrB;AACA;AAAA,EACF;AAEA,QAAM,UAAU,KAAK,KAAK,IAAI,SAAS,UAAU,CAAC,IAAI,YAAY,CAAC,EAAE,SAAS,KAAK,CAAC,MAAM;AAC1F,MAAI;AACF,UAAM,SAAS,MAAM,KAAK,SAAS,MAAM,QAAQ;AACjD,QAAI;AACF,YAAM,OAAO,UAAU,IAAI;AAC3B,YAAM,OAAO,MAAM,QAAQ;AAC3B,YAAM,OAAO,KAAK;AAAA,IACpB,UAAE;AACA,YAAM,OAAO,MAAM;AAAA,IACrB;AACA,UAAM,KAAK,SAAS,UAAU;AAC9B,UAAM,SAAS,GAAG;AAAA,EACpB,UAAE;AAGA,UAAM,GAAG,SAAS,EAAE,OAAO,KAAK,CAAC,EAAE,MAAM,MAAM,MAAS;AAAA,EAC1D;AACF;AAGA,eAAe,SAAS,KAA4B;AAClD,QAAM,SAAS,MAAM,KAAK,KAAK,GAAG;AAClC,MAAI;AACF,UAAM,OAAO,KAAK;AAAA,EACpB,UAAE;AACA,UAAM,OAAO,MAAM;AAAA,EACrB;AACF;","names":[]}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import { createRequire as __tenjinCreateRequire } from 'node:module'; const require = __tenjinCreateRequire(import.meta.url);
|
|
2
|
+
|
|
3
|
+
// package.json
|
|
4
|
+
var package_default = {
|
|
5
|
+
name: "tenjin-cli",
|
|
6
|
+
version: "0.1.0-alpha.2",
|
|
7
|
+
type: "module",
|
|
8
|
+
description: "Tenjin agent CLI for the x402 knowledge marketplace.",
|
|
9
|
+
license: "MIT",
|
|
10
|
+
repository: {
|
|
11
|
+
type: "git",
|
|
12
|
+
url: "git+https://github.com/BackTrackCo/tenjin-agent.git"
|
|
13
|
+
},
|
|
14
|
+
homepage: "https://tenjin.blog/agents",
|
|
15
|
+
bugs: "https://github.com/BackTrackCo/tenjin-agent/issues",
|
|
16
|
+
keywords: [
|
|
17
|
+
"x402",
|
|
18
|
+
"usdc",
|
|
19
|
+
"base",
|
|
20
|
+
"ai-agents",
|
|
21
|
+
"agent-payments",
|
|
22
|
+
"mcp",
|
|
23
|
+
"knowledge-marketplace",
|
|
24
|
+
"micropayments",
|
|
25
|
+
"claude",
|
|
26
|
+
"codex",
|
|
27
|
+
"cli"
|
|
28
|
+
],
|
|
29
|
+
bin: {
|
|
30
|
+
tenjin: "dist/index.js"
|
|
31
|
+
},
|
|
32
|
+
engines: {
|
|
33
|
+
node: ">=22"
|
|
34
|
+
},
|
|
35
|
+
files: [
|
|
36
|
+
"dist",
|
|
37
|
+
"skills",
|
|
38
|
+
"NOTICE.md"
|
|
39
|
+
],
|
|
40
|
+
packageManager: "pnpm@11.11.0",
|
|
41
|
+
scripts: {
|
|
42
|
+
build: "tsup",
|
|
43
|
+
test: "vitest run",
|
|
44
|
+
typecheck: "tsc --noEmit",
|
|
45
|
+
lint: "eslint .",
|
|
46
|
+
format: "prettier --write .",
|
|
47
|
+
"format:check": "prettier --check .",
|
|
48
|
+
check: "pnpm run build && pnpm run test",
|
|
49
|
+
"sync:skill": "node scripts/sync-skill.mjs",
|
|
50
|
+
"pack-smoke": "bash scripts/pack-smoke.sh",
|
|
51
|
+
changeset: "changeset",
|
|
52
|
+
prepublishOnly: "pnpm run build",
|
|
53
|
+
prepare: "git config core.hooksPath .githooks || true"
|
|
54
|
+
},
|
|
55
|
+
devDependencies: {
|
|
56
|
+
"@changesets/cli": "^2.31.1",
|
|
57
|
+
"@eslint/js": "^9",
|
|
58
|
+
"@types/node": "^25",
|
|
59
|
+
"@x402/core": "2.17.0",
|
|
60
|
+
"@x402/evm": "2.17.0",
|
|
61
|
+
"@x402/extensions": "2.17.0",
|
|
62
|
+
commander: "^14.0.1",
|
|
63
|
+
eslint: "^9",
|
|
64
|
+
"eslint-config-prettier": "^10",
|
|
65
|
+
ox: "0.14.30",
|
|
66
|
+
prettier: "^3",
|
|
67
|
+
tsup: "^8.5.0",
|
|
68
|
+
typescript: "^6",
|
|
69
|
+
"typescript-eslint": "^8",
|
|
70
|
+
viem: "^2.53.1",
|
|
71
|
+
vitest: "^4.1.9",
|
|
72
|
+
zod: "^4.4.3"
|
|
73
|
+
}
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
export {
|
|
77
|
+
package_default
|
|
78
|
+
};
|
|
79
|
+
//# sourceMappingURL=chunk-N62ROTMC.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../package.json"],"sourcesContent":["{\n \"name\": \"tenjin-cli\",\n \"version\": \"0.1.0-alpha.2\",\n \"type\": \"module\",\n \"description\": \"Tenjin agent CLI for the x402 knowledge marketplace.\",\n \"license\": \"MIT\",\n \"repository\": {\n \"type\": \"git\",\n \"url\": \"git+https://github.com/BackTrackCo/tenjin-agent.git\"\n },\n \"homepage\": \"https://tenjin.blog/agents\",\n \"bugs\": \"https://github.com/BackTrackCo/tenjin-agent/issues\",\n \"keywords\": [\n \"x402\",\n \"usdc\",\n \"base\",\n \"ai-agents\",\n \"agent-payments\",\n \"mcp\",\n \"knowledge-marketplace\",\n \"micropayments\",\n \"claude\",\n \"codex\",\n \"cli\"\n ],\n \"bin\": {\n \"tenjin\": \"dist/index.js\"\n },\n \"engines\": {\n \"node\": \">=22\"\n },\n \"files\": [\n \"dist\",\n \"skills\",\n \"NOTICE.md\"\n ],\n \"packageManager\": \"pnpm@11.11.0\",\n \"scripts\": {\n \"build\": \"tsup\",\n \"test\": \"vitest run\",\n \"typecheck\": \"tsc --noEmit\",\n \"lint\": \"eslint .\",\n \"format\": \"prettier --write .\",\n \"format:check\": \"prettier --check .\",\n \"check\": \"pnpm run build && pnpm run test\",\n \"sync:skill\": \"node scripts/sync-skill.mjs\",\n \"pack-smoke\": \"bash scripts/pack-smoke.sh\",\n \"changeset\": \"changeset\",\n \"prepublishOnly\": \"pnpm run build\",\n \"prepare\": \"git config core.hooksPath .githooks || true\"\n },\n \"devDependencies\": {\n \"@changesets/cli\": \"^2.31.1\",\n \"@eslint/js\": \"^9\",\n \"@types/node\": \"^25\",\n \"@x402/core\": \"2.17.0\",\n \"@x402/evm\": \"2.17.0\",\n \"@x402/extensions\": \"2.17.0\",\n \"commander\": \"^14.0.1\",\n \"eslint\": \"^9\",\n \"eslint-config-prettier\": \"^10\",\n \"ox\": \"0.14.30\",\n \"prettier\": \"^3\",\n \"tsup\": \"^8.5.0\",\n \"typescript\": \"^6\",\n \"typescript-eslint\": \"^8\",\n \"viem\": \"^2.53.1\",\n \"vitest\": \"^4.1.9\",\n \"zod\": \"^4.4.3\"\n }\n}\n"],"mappings":";;;AAAA;AAAA,EACE,MAAQ;AAAA,EACR,SAAW;AAAA,EACX,MAAQ;AAAA,EACR,aAAe;AAAA,EACf,SAAW;AAAA,EACX,YAAc;AAAA,IACZ,MAAQ;AAAA,IACR,KAAO;AAAA,EACT;AAAA,EACA,UAAY;AAAA,EACZ,MAAQ;AAAA,EACR,UAAY;AAAA,IACV;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAAA,EACA,KAAO;AAAA,IACL,QAAU;AAAA,EACZ;AAAA,EACA,SAAW;AAAA,IACT,MAAQ;AAAA,EACV;AAAA,EACA,OAAS;AAAA,IACP;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAAA,EACA,gBAAkB;AAAA,EAClB,SAAW;AAAA,IACT,OAAS;AAAA,IACT,MAAQ;AAAA,IACR,WAAa;AAAA,IACb,MAAQ;AAAA,IACR,QAAU;AAAA,IACV,gBAAgB;AAAA,IAChB,OAAS;AAAA,IACT,cAAc;AAAA,IACd,cAAc;AAAA,IACd,WAAa;AAAA,IACb,gBAAkB;AAAA,IAClB,SAAW;AAAA,EACb;AAAA,EACA,iBAAmB;AAAA,IACjB,mBAAmB;AAAA,IACnB,cAAc;AAAA,IACd,eAAe;AAAA,IACf,cAAc;AAAA,IACd,aAAa;AAAA,IACb,oBAAoB;AAAA,IACpB,WAAa;AAAA,IACb,QAAU;AAAA,IACV,0BAA0B;AAAA,IAC1B,IAAM;AAAA,IACN,UAAY;AAAA,IACZ,MAAQ;AAAA,IACR,YAAc;AAAA,IACd,qBAAqB;AAAA,IACrB,MAAQ;AAAA,IACR,QAAU;AAAA,IACV,KAAO;AAAA,EACT;AACF;","names":[]}
|