@garygentry/system1 0.3.0 → 0.3.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/dist/bundle/chunks/{bin-TCIHP5PC.mjs → bin-3EWFISFQ.mjs} +13 -42
- package/dist/bundle/chunks/{chunk-NUIZJRI6.mjs → chunk-4ZZ3ZSJN.mjs} +4 -2
- package/dist/bundle/chunks/{chunk-S5AIBUL7.mjs → chunk-5TUBFH7M.mjs} +225 -115
- package/dist/bundle/chunks/{chunk-4BSTNWLV.mjs → chunk-BGL272OK.mjs} +2 -2
- package/dist/bundle/chunks/{config-REALJZDR.mjs → config-UUPD2JL4.mjs} +36 -9
- package/dist/bundle/chunks/{decide-XVVRKQ3V.mjs → decide-AAXD3ITT.mjs} +3 -3
- package/dist/bundle/chunks/{doctor-TKFVFCZV.mjs → doctor-KPJ5KVLS.mjs} +2 -2
- package/dist/bundle/chunks/{misc-FHOVQJ2G.mjs → misc-IW4I3SO6.mjs} +39 -6
- package/dist/bundle/chunks/{route-NMFOTXLI.mjs → route-7N3J5NP6.mjs} +3 -3
- package/dist/bundle/chunks/{spec-734MPBKB.mjs → spec-RKA3K6ZZ.mjs} +23 -12
- package/dist/bundle/decide.mjs +1 -1
- package/package.json +1 -1
|
@@ -6,38 +6,10 @@ import {
|
|
|
6
6
|
VERSION,
|
|
7
7
|
emit,
|
|
8
8
|
extractFormat
|
|
9
|
-
} from "./chunk-
|
|
9
|
+
} from "./chunk-4ZZ3ZSJN.mjs";
|
|
10
10
|
|
|
11
11
|
// src/bin.ts
|
|
12
|
-
import { readFileSync
|
|
13
|
-
|
|
14
|
-
// src/bundled.ts
|
|
15
|
-
import { existsSync, readFileSync } from "node:fs";
|
|
16
|
-
import { dirname, join } from "node:path";
|
|
17
|
-
import { fileURLToPath } from "node:url";
|
|
18
|
-
var PACKAGE = "@garygentry/system1";
|
|
19
|
-
function bundledSpecsDir(from = fileURLToPath(import.meta.url)) {
|
|
20
|
-
const root = packageRoot(dirname(from));
|
|
21
|
-
if (!root) return void 0;
|
|
22
|
-
const own = join(root, "specs");
|
|
23
|
-
if (existsSync(own)) return own;
|
|
24
|
-
const checkout = join(root, "..", "..");
|
|
25
|
-
const plugin = join(checkout, "plugins", "system1", "specs");
|
|
26
|
-
return existsSync(join(checkout, "catalog.yaml")) && existsSync(plugin) ? plugin : void 0;
|
|
27
|
-
}
|
|
28
|
-
function packageRoot(start) {
|
|
29
|
-
for (let dir = start; ; dir = dirname(dir)) {
|
|
30
|
-
const manifest = join(dir, "package.json");
|
|
31
|
-
if (existsSync(manifest)) {
|
|
32
|
-
try {
|
|
33
|
-
if (JSON.parse(readFileSync(manifest, "utf8")).name === PACKAGE)
|
|
34
|
-
return dir;
|
|
35
|
-
} catch {
|
|
36
|
-
}
|
|
37
|
-
}
|
|
38
|
-
if (dirname(dir) === dir) return void 0;
|
|
39
|
-
}
|
|
40
|
-
}
|
|
12
|
+
import { readFileSync } from "node:fs";
|
|
41
13
|
|
|
42
14
|
// src/main.ts
|
|
43
15
|
var HELP = `decide ${VERSION} \u2014 typed, calibrated decisions for coding agents
|
|
@@ -92,23 +64,23 @@ async function main(argv, io) {
|
|
|
92
64
|
}
|
|
93
65
|
switch (command) {
|
|
94
66
|
case "ask":
|
|
95
|
-
return (await import("./decide-
|
|
67
|
+
return (await import("./decide-AAXD3ITT.mjs")).runAskCommand(rest, io, format);
|
|
96
68
|
case "many":
|
|
97
|
-
return (await import("./decide-
|
|
69
|
+
return (await import("./decide-AAXD3ITT.mjs")).runManyCommand(rest, io, format);
|
|
98
70
|
case "usage":
|
|
99
|
-
return (await import("./misc-
|
|
71
|
+
return (await import("./misc-IW4I3SO6.mjs")).runUsageCommand(rest, io, format);
|
|
100
72
|
case "config":
|
|
101
|
-
return (await import("./config-
|
|
73
|
+
return (await import("./config-UUPD2JL4.mjs")).runConfigCommand(rest, io, format);
|
|
102
74
|
case "spec":
|
|
103
|
-
return (await import("./spec-
|
|
75
|
+
return (await import("./spec-RKA3K6ZZ.mjs")).runSpecCommand(rest, io, format);
|
|
104
76
|
case "schema":
|
|
105
|
-
return (await import("./misc-
|
|
77
|
+
return (await import("./misc-IW4I3SO6.mjs")).runSchemaCommand(rest, io, format);
|
|
106
78
|
case "route":
|
|
107
|
-
return (await import("./route-
|
|
79
|
+
return (await import("./route-7N3J5NP6.mjs")).runRouteCommand(rest, io, format);
|
|
108
80
|
case "ping":
|
|
109
|
-
return (await import("./misc-
|
|
81
|
+
return (await import("./misc-IW4I3SO6.mjs")).runPingCommand(io, format);
|
|
110
82
|
case "doctor":
|
|
111
|
-
return (await import("./doctor-
|
|
83
|
+
return (await import("./doctor-KPJ5KVLS.mjs")).runDoctorCommand(io, format);
|
|
112
84
|
case "version":
|
|
113
85
|
case "--version":
|
|
114
86
|
case "-v":
|
|
@@ -138,7 +110,6 @@ process.exitCode = await main(process.argv.slice(2), {
|
|
|
138
110
|
err: line(process.stderr),
|
|
139
111
|
env: process.env,
|
|
140
112
|
cwd: process.cwd(),
|
|
141
|
-
readStdin: () =>
|
|
142
|
-
interactive: Boolean(process.stdin.isTTY && process.stdout.isTTY)
|
|
143
|
-
...bundledSpecsDir() ? { bundledSpecs: bundledSpecsDir() } : {}
|
|
113
|
+
readStdin: () => readFileSync(0, "utf8"),
|
|
114
|
+
interactive: Boolean(process.stdin.isTTY && process.stdout.isTTY)
|
|
144
115
|
});
|
|
@@ -70,7 +70,9 @@ var EXIT = {
|
|
|
70
70
|
egressRefused: 3,
|
|
71
71
|
budgetGuard: 4,
|
|
72
72
|
providerError: 5,
|
|
73
|
-
replayMiss: 6
|
|
73
|
+
replayMiss: 6,
|
|
74
|
+
/** `spec check --strict` only: the check ran, and an example did not pass. */
|
|
75
|
+
checkFailed: 7
|
|
74
76
|
};
|
|
75
77
|
var BY_CODE = {
|
|
76
78
|
"invalid-request": EXIT.usage,
|
|
@@ -145,7 +147,7 @@ function extractFormat(argv, fallback) {
|
|
|
145
147
|
}
|
|
146
148
|
|
|
147
149
|
// ../core/dist/version.js
|
|
148
|
-
var VERSION = "0.3.
|
|
150
|
+
var VERSION = "0.3.2";
|
|
149
151
|
var CLI_PACKAGE = "@garygentry/system1";
|
|
150
152
|
|
|
151
153
|
export {
|
|
@@ -9,7 +9,7 @@ import {
|
|
|
9
9
|
__require,
|
|
10
10
|
__toESM,
|
|
11
11
|
isDecisionsError
|
|
12
|
-
} from "./chunk-
|
|
12
|
+
} from "./chunk-4ZZ3ZSJN.mjs";
|
|
13
13
|
|
|
14
14
|
// ../../node_modules/.pnpm/yaml@2.9.1/node_modules/yaml/dist/nodes/identity.js
|
|
15
15
|
var require_identity = __commonJS({
|
|
@@ -9117,54 +9117,6 @@ var require_picomatch2 = __commonJS({
|
|
|
9117
9117
|
}
|
|
9118
9118
|
});
|
|
9119
9119
|
|
|
9120
|
-
// ../core/dist/config/load.js
|
|
9121
|
-
var import_yaml = __toESM(require_dist(), 1);
|
|
9122
|
-
import { existsSync, readFileSync, statSync } from "node:fs";
|
|
9123
|
-
import { homedir } from "node:os";
|
|
9124
|
-
import { dirname, join, resolve } from "node:path";
|
|
9125
|
-
|
|
9126
|
-
// ../core/dist/model/answers.js
|
|
9127
|
-
var DEFAULT_UNDECIDED_FLOOR = 0.15;
|
|
9128
|
-
function noulConfidence(answer) {
|
|
9129
|
-
return Math.abs(answer.noul - 0.5) * 2;
|
|
9130
|
-
}
|
|
9131
|
-
function confidenceOf(answer) {
|
|
9132
|
-
return answer.type === "noul" ? noulConfidence(answer) : answer.confidence;
|
|
9133
|
-
}
|
|
9134
|
-
function undecidedNames(answers, floor = DEFAULT_UNDECIDED_FLOOR) {
|
|
9135
|
-
return Object.entries(answers).filter(([, answer]) => confidenceOf(answer) <= floor).map(([name]) => name);
|
|
9136
|
-
}
|
|
9137
|
-
|
|
9138
|
-
// ../core/dist/model/profiles.js
|
|
9139
|
-
var PROFILES = [
|
|
9140
|
-
{
|
|
9141
|
-
id: "typesafe/jev-1.13",
|
|
9142
|
-
displayName: "TypeSafe Jev 1.13",
|
|
9143
|
-
transport: "openrouter-decisions",
|
|
9144
|
-
maxStateTokens: 32e3,
|
|
9145
|
-
// Measured 2026-09-22: 400 options is refused upstream with "at most 255 choices".
|
|
9146
|
-
maxChoices: 255,
|
|
9147
|
-
usdPerInputToken: 0.042 / 1e6,
|
|
9148
|
-
usdPerOutputToken: 0,
|
|
9149
|
-
priceAsOf: "2026-09-19",
|
|
9150
|
-
undecidedFloor: DEFAULT_UNDECIDED_FLOOR,
|
|
9151
|
-
calibrated: true
|
|
9152
|
-
}
|
|
9153
|
-
];
|
|
9154
|
-
var DEFAULT_MODEL_ID = "typesafe/jev-1.13";
|
|
9155
|
-
function resolveProfile(id, profiles = PROFILES) {
|
|
9156
|
-
const exact = profiles.find((p) => p.id === id);
|
|
9157
|
-
if (exact)
|
|
9158
|
-
return exact;
|
|
9159
|
-
const family = profiles.find((p) => new RegExp(`^${escapeRegExp(p.id)}-\\d{8}$`).test(id));
|
|
9160
|
-
if (family)
|
|
9161
|
-
return { ...family, id };
|
|
9162
|
-
throw new DecisionsError("unknown-model", `No profile for model "${id}". Known: ${profiles.map((p) => p.id).join(", ")}.`, { model: id, known: profiles.map((p) => p.id) });
|
|
9163
|
-
}
|
|
9164
|
-
function escapeRegExp(text) {
|
|
9165
|
-
return text.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
9166
|
-
}
|
|
9167
|
-
|
|
9168
9120
|
// ../core/dist/route/route.js
|
|
9169
9121
|
var ROUTE_DEFAULTS = {
|
|
9170
9122
|
enabled: true,
|
|
@@ -9266,7 +9218,58 @@ function route(prompt, config) {
|
|
|
9266
9218
|
};
|
|
9267
9219
|
}
|
|
9268
9220
|
|
|
9221
|
+
// ../core/dist/config/load.js
|
|
9222
|
+
var import_yaml = __toESM(require_dist(), 1);
|
|
9223
|
+
import { existsSync, readFileSync, statSync } from "node:fs";
|
|
9224
|
+
import { homedir } from "node:os";
|
|
9225
|
+
import { dirname, join, resolve } from "node:path";
|
|
9226
|
+
|
|
9227
|
+
// ../core/dist/model/answers.js
|
|
9228
|
+
var DEFAULT_UNDECIDED_FLOOR = 0.15;
|
|
9229
|
+
function noulConfidence(answer) {
|
|
9230
|
+
return Math.abs(answer.noul - 0.5) * 2;
|
|
9231
|
+
}
|
|
9232
|
+
function confidenceOf(answer) {
|
|
9233
|
+
return answer.type === "noul" ? noulConfidence(answer) : answer.confidence;
|
|
9234
|
+
}
|
|
9235
|
+
function undecidedNames(answers, floor = DEFAULT_UNDECIDED_FLOOR) {
|
|
9236
|
+
return Object.entries(answers).filter(([, answer]) => confidenceOf(answer) <= floor).map(([name]) => name);
|
|
9237
|
+
}
|
|
9238
|
+
|
|
9239
|
+
// ../core/dist/model/profiles.js
|
|
9240
|
+
var JEV_CALL_OVERHEAD_TOKENS = 300;
|
|
9241
|
+
var PROFILES = [
|
|
9242
|
+
{
|
|
9243
|
+
id: "typesafe/jev-1.13",
|
|
9244
|
+
displayName: "TypeSafe Jev 1.13",
|
|
9245
|
+
transport: "openrouter-decisions",
|
|
9246
|
+
maxStateTokens: 32e3,
|
|
9247
|
+
// Measured 2026-09-22: 400 options is refused upstream with "at most 255 choices".
|
|
9248
|
+
maxChoices: 255,
|
|
9249
|
+
callOverheadTokens: JEV_CALL_OVERHEAD_TOKENS,
|
|
9250
|
+
usdPerInputToken: 0.042 / 1e6,
|
|
9251
|
+
usdPerOutputToken: 0,
|
|
9252
|
+
priceAsOf: "2026-09-19",
|
|
9253
|
+
undecidedFloor: DEFAULT_UNDECIDED_FLOOR,
|
|
9254
|
+
calibrated: true
|
|
9255
|
+
}
|
|
9256
|
+
];
|
|
9257
|
+
var DEFAULT_MODEL_ID = "typesafe/jev-1.13";
|
|
9258
|
+
function resolveProfile(id, profiles = PROFILES) {
|
|
9259
|
+
const exact = profiles.find((p) => p.id === id);
|
|
9260
|
+
if (exact)
|
|
9261
|
+
return exact;
|
|
9262
|
+
const family = profiles.find((p) => new RegExp(`^${escapeRegExp(p.id)}-\\d{8}$`).test(id));
|
|
9263
|
+
if (family)
|
|
9264
|
+
return { ...family, id };
|
|
9265
|
+
throw new DecisionsError("unknown-model", `No profile for model "${id}". Known: ${profiles.map((p) => p.id).join(", ")}.`, { model: id, known: profiles.map((p) => p.id) });
|
|
9266
|
+
}
|
|
9267
|
+
function escapeRegExp(text) {
|
|
9268
|
+
return text.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
9269
|
+
}
|
|
9270
|
+
|
|
9269
9271
|
// ../core/dist/model/validate.js
|
|
9272
|
+
var QUESTION_KEYS = ["type", "instructions", "criteria"];
|
|
9270
9273
|
function assertQuestionSet(questions) {
|
|
9271
9274
|
const problems = [];
|
|
9272
9275
|
if (!isObject(questions) || Object.keys(questions).length === 0) {
|
|
@@ -9277,6 +9280,10 @@ function assertQuestionSet(questions) {
|
|
|
9277
9280
|
problems.push(`${name}: must be an object`);
|
|
9278
9281
|
continue;
|
|
9279
9282
|
}
|
|
9283
|
+
const extra = Object.keys(q).filter((k) => !QUESTION_KEYS.includes(k));
|
|
9284
|
+
if (extra.length > 0) {
|
|
9285
|
+
problems.push(`${name}: unknown key(s) ${extra.join(", ")} (a question has type, instructions, criteria)`);
|
|
9286
|
+
}
|
|
9280
9287
|
if (typeof q.instructions !== "string" || q.instructions.trim() === "") {
|
|
9281
9288
|
problems.push(`${name}: instructions must be a non-empty string`);
|
|
9282
9289
|
}
|
|
@@ -9556,14 +9563,20 @@ function loadConfig(options = {}) {
|
|
|
9556
9563
|
const repoFile = repoConfigPath(repoRoot);
|
|
9557
9564
|
const user = readLayer(userFile);
|
|
9558
9565
|
const repo = readLayer(repoFile);
|
|
9566
|
+
const warnings = [...unknownKeys(user, userFile, "user"), ...unknownKeys(repo, repoFile, "repo")];
|
|
9567
|
+
const layers2 = [
|
|
9568
|
+
{ layer: repo, file: repoFile },
|
|
9569
|
+
{ layer: user, file: userFile }
|
|
9570
|
+
];
|
|
9571
|
+
const pickFrom = (path, rule) => pick(path, rule, layers2, warnings);
|
|
9559
9572
|
const merged = {
|
|
9560
|
-
model:
|
|
9561
|
-
endpoint:
|
|
9562
|
-
concurrency:
|
|
9563
|
-
timeoutMs:
|
|
9573
|
+
model: pickFrom("model", TEXT) ?? DEFAULTS.model,
|
|
9574
|
+
endpoint: pickFrom("endpoint", URL_TEXT) ?? DEFAULTS.endpoint,
|
|
9575
|
+
concurrency: pickFrom("concurrency", WHOLE) ?? DEFAULTS.concurrency,
|
|
9576
|
+
timeoutMs: pickFrom("timeoutMs", POSITIVE) ?? DEFAULTS.timeoutMs,
|
|
9564
9577
|
budget: {
|
|
9565
|
-
maxCalls:
|
|
9566
|
-
maxUsd:
|
|
9578
|
+
maxCalls: pickFrom("budget.maxCalls", NON_NEGATIVE) ?? DEFAULTS.budget.maxCalls,
|
|
9579
|
+
maxUsd: pickFrom("budget.maxUsd", NON_NEGATIVE) ?? DEFAULTS.budget.maxUsd
|
|
9567
9580
|
},
|
|
9568
9581
|
egress: {
|
|
9569
9582
|
consent: readConsent(repo, repoFile),
|
|
@@ -9572,7 +9585,7 @@ function loadConfig(options = {}) {
|
|
|
9572
9585
|
...stringList(repo, "egress.exclude", repoFile)
|
|
9573
9586
|
]
|
|
9574
9587
|
},
|
|
9575
|
-
profiles: [...profileList(user, userFile), ...profileList(repo, repoFile)],
|
|
9588
|
+
profiles: [...profileList(user, userFile, warnings), ...profileList(repo, repoFile, warnings)],
|
|
9576
9589
|
route: readRoute(user, userFile, repo, repoFile, env)
|
|
9577
9590
|
};
|
|
9578
9591
|
const key = resolveApiKey(env, userDir);
|
|
@@ -9591,11 +9604,15 @@ function loadConfig(options = {}) {
|
|
|
9591
9604
|
...user ? { user: userFile } : {},
|
|
9592
9605
|
...repo ? { repo: repoFile } : {},
|
|
9593
9606
|
...key?.file ? { credentials: key.file } : {}
|
|
9594
|
-
}
|
|
9607
|
+
},
|
|
9608
|
+
warnings
|
|
9595
9609
|
};
|
|
9596
9610
|
}
|
|
9597
9611
|
function allProfiles(config) {
|
|
9598
|
-
|
|
9612
|
+
const byId = /* @__PURE__ */ new Map();
|
|
9613
|
+
for (const profile of [...PROFILES, ...config.profiles])
|
|
9614
|
+
byId.set(profile.id, profile);
|
|
9615
|
+
return [...byId.values()];
|
|
9599
9616
|
}
|
|
9600
9617
|
function readLayer(file) {
|
|
9601
9618
|
if (!existsSync(file))
|
|
@@ -9615,25 +9632,73 @@ function readLayer(file) {
|
|
|
9615
9632
|
}
|
|
9616
9633
|
return parsed;
|
|
9617
9634
|
}
|
|
9618
|
-
|
|
9619
|
-
|
|
9620
|
-
|
|
9621
|
-
|
|
9622
|
-
|
|
9635
|
+
var KNOWN = {
|
|
9636
|
+
"": ["model", "endpoint", "concurrency", "timeoutMs", "budget", "egress", "profiles", "route"],
|
|
9637
|
+
budget: ["maxCalls", "maxUsd"],
|
|
9638
|
+
egress: ["consent", "exclude"]
|
|
9639
|
+
};
|
|
9640
|
+
function unknownKeys(layer, file, which2) {
|
|
9641
|
+
if (!layer)
|
|
9642
|
+
return [];
|
|
9643
|
+
const warnings = Object.keys(layer).filter((k) => !KNOWN[""]?.includes(k)).map((key) => `${file}: unknown key ${key}`);
|
|
9644
|
+
for (const section2 of ["budget", "egress"]) {
|
|
9645
|
+
const value = layer[section2];
|
|
9646
|
+
if (value === void 0 || value === null)
|
|
9647
|
+
continue;
|
|
9648
|
+
if (!isMapping(value)) {
|
|
9649
|
+
warnings.push(`${file}: ${section2} must be a mapping (ignored)`);
|
|
9650
|
+
continue;
|
|
9651
|
+
}
|
|
9652
|
+
for (const key of Object.keys(value)) {
|
|
9653
|
+
if (!KNOWN[section2]?.includes(key))
|
|
9654
|
+
warnings.push(`${file}: unknown key ${section2}.${key}`);
|
|
9655
|
+
}
|
|
9623
9656
|
}
|
|
9624
|
-
|
|
9657
|
+
const egress = layer.egress;
|
|
9658
|
+
if (which2 === "user" && isMapping(egress) && egress.consent !== void 0) {
|
|
9659
|
+
warnings.push(`${file}: egress.consent is read only from the repo file (ignored)`);
|
|
9660
|
+
}
|
|
9661
|
+
return warnings;
|
|
9625
9662
|
}
|
|
9626
|
-
|
|
9627
|
-
|
|
9628
|
-
|
|
9629
|
-
|
|
9630
|
-
|
|
9663
|
+
var TEXT = { ok: (v) => typeof v === "string", expected: "text" };
|
|
9664
|
+
var URL_TEXT = {
|
|
9665
|
+
ok: (v) => typeof v === "string" && URL.canParse(v) && /^https?:$/.test(new URL(v).protocol),
|
|
9666
|
+
expected: "an http(s) URL"
|
|
9667
|
+
};
|
|
9668
|
+
var WHOLE = {
|
|
9669
|
+
ok: (v) => Number.isInteger(v) && v >= 1,
|
|
9670
|
+
expected: "a whole number of at least 1"
|
|
9671
|
+
};
|
|
9672
|
+
var POSITIVE = {
|
|
9673
|
+
ok: (v) => typeof v === "number" && Number.isFinite(v) && v > 0,
|
|
9674
|
+
expected: "a number above 0"
|
|
9675
|
+
};
|
|
9676
|
+
var NON_NEGATIVE = {
|
|
9677
|
+
ok: (v) => typeof v === "number" && Number.isFinite(v) && v >= 0,
|
|
9678
|
+
expected: "a number of at least 0"
|
|
9679
|
+
};
|
|
9680
|
+
function pick(path, rule, layers2, warnings) {
|
|
9681
|
+
let found2;
|
|
9682
|
+
for (const { layer, file } of layers2) {
|
|
9683
|
+
const [head, key] = path.split(".");
|
|
9684
|
+
let value = layer?.[head];
|
|
9685
|
+
if (key !== void 0)
|
|
9686
|
+
value = isMapping(value) ? value[key] : void 0;
|
|
9687
|
+
if (value === void 0 || value === null)
|
|
9688
|
+
continue;
|
|
9689
|
+
if (!rule.ok(value))
|
|
9690
|
+
warnings.push(`${file}: ${path} must be ${rule.expected} (ignored)`);
|
|
9691
|
+
else if (found2 === void 0)
|
|
9692
|
+
found2 = value;
|
|
9631
9693
|
}
|
|
9632
|
-
return
|
|
9694
|
+
return found2;
|
|
9695
|
+
}
|
|
9696
|
+
function isMapping(value) {
|
|
9697
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
9633
9698
|
}
|
|
9634
9699
|
function readConsent(repo, file) {
|
|
9635
9700
|
const consent = repo?.egress?.consent;
|
|
9636
|
-
if (consent === void 0)
|
|
9701
|
+
if (consent === void 0 || consent === null)
|
|
9637
9702
|
return { granted: false };
|
|
9638
9703
|
if (typeof consent !== "object" || consent === null || typeof consent.granted !== "boolean") {
|
|
9639
9704
|
throw new DecisionsError("config-error", `${file}: egress.consent must be {granted: true|false, at?, by?}`, { file });
|
|
@@ -9647,7 +9712,7 @@ function readConsent(repo, file) {
|
|
|
9647
9712
|
}
|
|
9648
9713
|
function stringList(layer, path, file) {
|
|
9649
9714
|
const value = layer?.egress?.exclude;
|
|
9650
|
-
if (value === void 0)
|
|
9715
|
+
if (value === void 0 || value === null)
|
|
9651
9716
|
return [];
|
|
9652
9717
|
if (!Array.isArray(value) || !value.every((v) => typeof v === "string")) {
|
|
9653
9718
|
throw new DecisionsError("config-error", `${file}: ${path} must be a list of glob patterns`, {
|
|
@@ -9656,29 +9721,57 @@ function stringList(layer, path, file) {
|
|
|
9656
9721
|
}
|
|
9657
9722
|
return value;
|
|
9658
9723
|
}
|
|
9659
|
-
|
|
9724
|
+
var PROFILE_FIELDS = [
|
|
9725
|
+
"id",
|
|
9726
|
+
"displayName",
|
|
9727
|
+
"transport",
|
|
9728
|
+
"maxStateTokens",
|
|
9729
|
+
"maxChoices",
|
|
9730
|
+
"callOverheadTokens",
|
|
9731
|
+
"usdPerInputToken",
|
|
9732
|
+
"usdPerOutputToken",
|
|
9733
|
+
"priceAsOf",
|
|
9734
|
+
"undecidedFloor",
|
|
9735
|
+
"calibrated"
|
|
9736
|
+
];
|
|
9737
|
+
function profileList(layer, file, warnings) {
|
|
9660
9738
|
const value = layer?.profiles;
|
|
9661
|
-
if (value === void 0)
|
|
9739
|
+
if (value === void 0 || value === null)
|
|
9662
9740
|
return [];
|
|
9663
9741
|
if (!Array.isArray(value))
|
|
9664
9742
|
throw new DecisionsError("config-error", `${file}: profiles must be a list`, { file });
|
|
9665
9743
|
return value.map((p, i) => {
|
|
9666
|
-
const profile = p;
|
|
9744
|
+
const profile = { ...p };
|
|
9745
|
+
for (const [key, v] of Object.entries(profile)) {
|
|
9746
|
+
if (v === null && PROFILE_FIELDS.includes(key)) {
|
|
9747
|
+
delete profile[key];
|
|
9748
|
+
}
|
|
9749
|
+
}
|
|
9667
9750
|
const ok = typeof profile.id === "string" && typeof profile.maxStateTokens === "number" && typeof profile.usdPerInputToken === "number" && typeof profile.undecidedFloor === "number";
|
|
9668
9751
|
if (!ok) {
|
|
9669
9752
|
throw new DecisionsError("config-error", `${file}: profiles[${i}] needs id, maxStateTokens, usdPerInputToken and undecidedFloor`, { file });
|
|
9670
9753
|
}
|
|
9754
|
+
if (profile.callOverheadTokens !== void 0 && !(Number.isInteger(profile.callOverheadTokens) && profile.callOverheadTokens >= 0)) {
|
|
9755
|
+
throw new DecisionsError("config-error", `${file}: profiles[${i}].callOverheadTokens must be a whole number of at least 0`, { file });
|
|
9756
|
+
}
|
|
9671
9757
|
if (profile.maxChoices !== void 0 && !(Number.isInteger(profile.maxChoices) && profile.maxChoices >= 2)) {
|
|
9672
9758
|
throw new DecisionsError("config-error", `${file}: profiles[${i}].maxChoices must be a whole number of at least 2`, { file });
|
|
9673
9759
|
}
|
|
9760
|
+
const extra = Object.keys(profile).filter((k) => !PROFILE_FIELDS.includes(k));
|
|
9761
|
+
for (const key of extra) {
|
|
9762
|
+
warnings.push(`${file}: unknown key profiles[${i}].${key} (ignored)`);
|
|
9763
|
+
delete profile[key];
|
|
9764
|
+
}
|
|
9674
9765
|
return {
|
|
9675
9766
|
displayName: profile.id,
|
|
9676
9767
|
transport: "openrouter-decisions",
|
|
9677
9768
|
usdPerOutputToken: 0,
|
|
9678
9769
|
priceAsOf: "unknown",
|
|
9679
9770
|
calibrated: true,
|
|
9680
|
-
// Same wire contract as Jev unless the config says otherwise.
|
|
9771
|
+
// Same wire contract as Jev unless the config says otherwise. The overhead is
|
|
9772
|
+
// Jev's measured one: unknown for another model, but it errs toward stopping.
|
|
9681
9773
|
maxChoices: 255,
|
|
9774
|
+
callOverheadTokens: JEV_CALL_OVERHEAD_TOKENS,
|
|
9682
9775
|
...profile
|
|
9683
9776
|
};
|
|
9684
9777
|
});
|
|
@@ -9784,7 +9877,7 @@ function setConsent(repoRoot, granted, by, now = /* @__PURE__ */ new Date()) {
|
|
|
9784
9877
|
function assertConsent(consent, repoRoot) {
|
|
9785
9878
|
if (consent.granted)
|
|
9786
9879
|
return;
|
|
9787
|
-
throw new DecisionsError("egress-refused", `This repo has not agreed to send content to the decision model's provider. Consent is the user's:
|
|
9880
|
+
throw new DecisionsError("egress-refused", `This repo has not agreed to send content to the decision model's provider. Consent is the user's, and an agent must not grant it: the user runs \`decide config egress allow\` themselves in a terminal in ${repoRoot}, or through their agent prompt's shell escape (not as a chat message) with --confirm added. The setup skill explains what gets sent. Replay of recorded answers works without consent.`, { repoRoot });
|
|
9788
9881
|
}
|
|
9789
9882
|
|
|
9790
9883
|
// ../core/dist/egress/exclude.js
|
|
@@ -19433,40 +19526,36 @@ function describeExpectation(expectation) {
|
|
|
19433
19526
|
}
|
|
19434
19527
|
|
|
19435
19528
|
// ../core/dist/spec/spec.js
|
|
19436
|
-
var
|
|
19529
|
+
var CLOSED = { additionalProperties: false };
|
|
19530
|
+
var Threshold = typebox_exports.Object({ value: typebox_exports.Number(), why: typebox_exports.String({ minLength: 1 }) }, CLOSED);
|
|
19437
19531
|
var SPEC_FORMAT = 1;
|
|
19438
|
-
var SpecSchema = typebox_exports.Object(
|
|
19439
|
-
|
|
19440
|
-
|
|
19441
|
-
|
|
19442
|
-
|
|
19443
|
-
|
|
19444
|
-
|
|
19445
|
-
|
|
19446
|
-
|
|
19447
|
-
|
|
19448
|
-
|
|
19449
|
-
|
|
19450
|
-
|
|
19451
|
-
|
|
19452
|
-
|
|
19453
|
-
|
|
19454
|
-
|
|
19455
|
-
|
|
19456
|
-
|
|
19457
|
-
|
|
19458
|
-
|
|
19459
|
-
|
|
19460
|
-
|
|
19461
|
-
|
|
19462
|
-
|
|
19463
|
-
|
|
19464
|
-
|
|
19465
|
-
},
|
|
19466
|
-
// A misspelled key (`kepe:`, `exepct:`) must fail rather than silently
|
|
19467
|
-
// becoming no policy at all.
|
|
19468
|
-
{ additionalProperties: false }
|
|
19469
|
-
);
|
|
19532
|
+
var SpecSchema = typebox_exports.Object({
|
|
19533
|
+
/** Spec file format. Absent means 1; a newer one is refused, not guessed. */
|
|
19534
|
+
version: typebox_exports.Optional(typebox_exports.Integer({ minimum: 1 })),
|
|
19535
|
+
description: typebox_exports.String({ minLength: 1 }),
|
|
19536
|
+
questions: typebox_exports.Record(typebox_exports.String(), typebox_exports.Unknown()),
|
|
19537
|
+
keep: typebox_exports.Optional(typebox_exports.Array(typebox_exports.String())),
|
|
19538
|
+
sort: typebox_exports.Optional(typebox_exports.String()),
|
|
19539
|
+
policy: typebox_exports.Optional(typebox_exports.Object({ thresholds: typebox_exports.Optional(typebox_exports.Record(typebox_exports.String(), Threshold)) }, CLOSED)),
|
|
19540
|
+
source: typebox_exports.Optional(typebox_exports.Object({
|
|
19541
|
+
glob: typebox_exports.Optional(typebox_exports.Array(typebox_exports.String())),
|
|
19542
|
+
file: typebox_exports.Optional(typebox_exports.String()),
|
|
19543
|
+
jsonl: typebox_exports.Optional(typebox_exports.String()),
|
|
19544
|
+
diff: typebox_exports.Optional(typebox_exports.String()),
|
|
19545
|
+
split: typebox_exports.Optional(typebox_exports.String())
|
|
19546
|
+
}, CLOSED)),
|
|
19547
|
+
examples: typebox_exports.Optional(typebox_exports.Array(typebox_exports.Object({
|
|
19548
|
+
id: typebox_exports.String({ minLength: 1 }),
|
|
19549
|
+
/** The text (or a JSON value, sent as its JSON text) to judge. Give this or `file`. */
|
|
19550
|
+
state: typebox_exports.Optional(typebox_exports.Unknown()),
|
|
19551
|
+
/** A repo file to judge, `path` or `path:START-END`. Give this or `state`. */
|
|
19552
|
+
file: typebox_exports.Optional(typebox_exports.String()),
|
|
19553
|
+
expect: typebox_exports.Optional(typebox_exports.Record(typebox_exports.String(), typebox_exports.Unknown()))
|
|
19554
|
+
}, CLOSED))),
|
|
19555
|
+
provenance: typebox_exports.Optional(typebox_exports.Record(typebox_exports.String(), typebox_exports.Unknown())),
|
|
19556
|
+
/** Anything else a team wants to carry, ignored by the engine. */
|
|
19557
|
+
meta: typebox_exports.Optional(typebox_exports.Record(typebox_exports.String(), typebox_exports.Unknown()))
|
|
19558
|
+
}, CLOSED);
|
|
19470
19559
|
var NAME = /^[a-z0-9][a-z0-9._-]*$/;
|
|
19471
19560
|
function parseSpec(text, file, origin) {
|
|
19472
19561
|
let raw;
|
|
@@ -20116,7 +20205,7 @@ function ledgerFor(ctx) {
|
|
|
20116
20205
|
|
|
20117
20206
|
// ../core/dist/run/budget.js
|
|
20118
20207
|
function project2(profile, tokensPerCall) {
|
|
20119
|
-
const estimatedInputTokens = tokensPerCall.reduce((
|
|
20208
|
+
const estimatedInputTokens = tokensPerCall.reduce((sum, tokens) => sum + tokens + profile.callOverheadTokens, 0);
|
|
20120
20209
|
return {
|
|
20121
20210
|
basis: "projected",
|
|
20122
20211
|
calls: tokensPerCall.length,
|
|
@@ -20125,6 +20214,16 @@ function project2(profile, tokensPerCall) {
|
|
|
20125
20214
|
priceAsOf: profile.priceAsOf
|
|
20126
20215
|
};
|
|
20127
20216
|
}
|
|
20217
|
+
function combineProjections(profile, parts) {
|
|
20218
|
+
const estimatedInputTokens = parts.reduce((sum, p) => sum + p.estimatedInputTokens, 0);
|
|
20219
|
+
return {
|
|
20220
|
+
basis: "projected",
|
|
20221
|
+
calls: parts.reduce((sum, p) => sum + p.calls, 0),
|
|
20222
|
+
estimatedInputTokens,
|
|
20223
|
+
projectedUsd: estimatedInputTokens * profile.usdPerInputToken,
|
|
20224
|
+
priceAsOf: profile.priceAsOf
|
|
20225
|
+
};
|
|
20226
|
+
}
|
|
20128
20227
|
function checkBudget(projection, budget, confirmed) {
|
|
20129
20228
|
if (confirmed)
|
|
20130
20229
|
return;
|
|
@@ -20457,18 +20556,26 @@ async function runDoctor(options) {
|
|
|
20457
20556
|
return report2(void 0, false);
|
|
20458
20557
|
}
|
|
20459
20558
|
const { config } = ctx;
|
|
20559
|
+
if (config.warnings.length > 0) {
|
|
20560
|
+
checks.push({
|
|
20561
|
+
name: "config-keys",
|
|
20562
|
+
status: "warn",
|
|
20563
|
+
detail: `ignored: ${config.warnings.join("; ")}`,
|
|
20564
|
+
fix: "correct or remove these keys (docs/configuration.md lists every key)"
|
|
20565
|
+
});
|
|
20566
|
+
}
|
|
20460
20567
|
checks.push(config.apiKey ? { name: "key", status: "ok", detail: `OPENROUTER_API_KEY present (${config.apiKeySource})` } : {
|
|
20461
20568
|
name: "key",
|
|
20462
20569
|
status: "warn",
|
|
20463
20570
|
detail: "no API key: only replay works",
|
|
20464
20571
|
// The file this shell would read: XDG_CONFIG_HOME moves it.
|
|
20465
|
-
fix: `set OPENROUTER_API_KEY, or write \`openrouter_api_key: <key>\` to ${join5(userConfigDir(env, options.home), "credentials")} (chmod 600)`
|
|
20572
|
+
fix: `set OPENROUTER_API_KEY, or write \`openrouter_api_key: <key>\` to ${join5(userConfigDir(env, options.home), "credentials")} (create its directory first; chmod 600)`
|
|
20466
20573
|
});
|
|
20467
20574
|
checks.push(config.egress.consent.granted ? { name: "consent", status: "ok", detail: `egress consent granted for ${config.repoRoot}` } : {
|
|
20468
20575
|
name: "consent",
|
|
20469
20576
|
status: "warn",
|
|
20470
20577
|
detail: `no egress consent for ${config.repoRoot}: live calls are refused`,
|
|
20471
|
-
fix: "the user
|
|
20578
|
+
fix: "if the user agrees, they grant it themselves (an agent must not): `decide config egress allow` in a terminal in this repo, or through their agent prompt's shell escape (not as a chat message) with --confirm added"
|
|
20472
20579
|
});
|
|
20473
20580
|
checks.push(routeCheck(config.route));
|
|
20474
20581
|
let reach;
|
|
@@ -20669,8 +20776,8 @@ async function runSpecCheck(ctx, rawInput) {
|
|
|
20669
20776
|
const decider = deciderFor(ctx, profile, input.mode ?? "replay");
|
|
20670
20777
|
if (decider.mode !== "replay") {
|
|
20671
20778
|
assertConsent(ctx.config.egress.consent, root);
|
|
20672
|
-
const
|
|
20673
|
-
checkBudget(
|
|
20779
|
+
const parts = prepared.flatMap((p) => p.prep ? [p.prep.projection] : []);
|
|
20780
|
+
checkBudget(combineProjections(profile, parts), ctx.config.budget, input.confirm ?? false);
|
|
20674
20781
|
}
|
|
20675
20782
|
const results = [];
|
|
20676
20783
|
const usages = [];
|
|
@@ -20792,10 +20899,13 @@ function nonEmpty3(value) {
|
|
|
20792
20899
|
}
|
|
20793
20900
|
|
|
20794
20901
|
export {
|
|
20902
|
+
activeTriggers,
|
|
20795
20903
|
repoConfigPath,
|
|
20796
20904
|
loadConfig,
|
|
20905
|
+
allProfiles,
|
|
20797
20906
|
setConsent,
|
|
20798
20907
|
DEFAULT_EXCLUDES,
|
|
20908
|
+
probeUrl,
|
|
20799
20909
|
ping,
|
|
20800
20910
|
parseFileRef,
|
|
20801
20911
|
exampleProblems,
|
|
@@ -2,10 +2,10 @@ import { createRequire as __decideRequire } from "node:module"; const require =
|
|
|
2
2
|
import {
|
|
3
3
|
parseFileRef,
|
|
4
4
|
parseQuestionSet
|
|
5
|
-
} from "./chunk-
|
|
5
|
+
} from "./chunk-5TUBFH7M.mjs";
|
|
6
6
|
import {
|
|
7
7
|
DecisionsError
|
|
8
|
-
} from "./chunk-
|
|
8
|
+
} from "./chunk-4ZZ3ZSJN.mjs";
|
|
9
9
|
|
|
10
10
|
// src/args.ts
|
|
11
11
|
import { readFileSync } from "node:fs";
|
|
@@ -1,18 +1,20 @@
|
|
|
1
1
|
import { createRequire as __decideRequire } from "node:module"; const require = __decideRequire(import.meta.url);
|
|
2
2
|
import {
|
|
3
3
|
typedParse
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-BGL272OK.mjs";
|
|
5
5
|
import {
|
|
6
6
|
DEFAULT_EXCLUDES,
|
|
7
|
+
activeTriggers,
|
|
8
|
+
allProfiles,
|
|
7
9
|
createContext,
|
|
8
10
|
loadConfig,
|
|
9
11
|
repoConfigPath,
|
|
10
12
|
setConsent
|
|
11
|
-
} from "./chunk-
|
|
13
|
+
} from "./chunk-5TUBFH7M.mjs";
|
|
12
14
|
import {
|
|
13
15
|
DecisionsError,
|
|
14
16
|
emit
|
|
15
|
-
} from "./chunk-
|
|
17
|
+
} from "./chunk-4ZZ3ZSJN.mjs";
|
|
16
18
|
|
|
17
19
|
// src/commands/config.ts
|
|
18
20
|
function runConfigCommand(argv, io, format) {
|
|
@@ -49,12 +51,17 @@ function body(argv, io) {
|
|
|
49
51
|
if (!io.interactive && !values.confirm) {
|
|
50
52
|
throw new DecisionsError(
|
|
51
53
|
"egress-refused",
|
|
52
|
-
"Egress consent is the user's decision.
|
|
54
|
+
"Egress consent is the user's decision. An agent must not grant it, with or without --confirm: show the user this message instead. The user grants it by typing `decide config egress allow` in a terminal at the repo root. If they run it through their agent prompt's shell escape instead (not as a chat message), there is no terminal, so they add --confirm to say the decision is theirs."
|
|
53
55
|
);
|
|
54
56
|
}
|
|
55
57
|
return {
|
|
56
58
|
egress: {
|
|
57
|
-
|
|
59
|
+
// Record which route granted it: a terminal, or --confirm without one.
|
|
60
|
+
consent: setConsent(
|
|
61
|
+
config.repoRoot,
|
|
62
|
+
true,
|
|
63
|
+
values.by ?? (io.interactive ? "decide config" : "decide config --confirm")
|
|
64
|
+
),
|
|
58
65
|
file,
|
|
59
66
|
changed: true
|
|
60
67
|
}
|
|
@@ -82,6 +89,7 @@ function show(io, cwd) {
|
|
|
82
89
|
model: config.model,
|
|
83
90
|
endpoint: config.endpoint,
|
|
84
91
|
concurrency: config.concurrency,
|
|
92
|
+
timeoutMs: config.timeoutMs,
|
|
85
93
|
budget: config.budget,
|
|
86
94
|
egress: {
|
|
87
95
|
consent: config.egress.consent,
|
|
@@ -92,8 +100,15 @@ function show(io, cwd) {
|
|
|
92
100
|
replay: config.replay,
|
|
93
101
|
session: config.session ?? null,
|
|
94
102
|
sessionOrigin: config.sessionOrigin ?? null,
|
|
103
|
+
/**
|
|
104
|
+
* The profiles in effect for the ids the config files set, one per id: an
|
|
105
|
+
* override of a built-in shows once. Built-ins nobody overrides are not repeated.
|
|
106
|
+
*/
|
|
107
|
+
profiles: allProfiles(config).filter((p) => config.profiles.some((c) => c.id === p.id)),
|
|
108
|
+
route: config.route,
|
|
95
109
|
files: config.layers,
|
|
96
|
-
specDirs: ctx.specDirs
|
|
110
|
+
specDirs: ctx.specDirs,
|
|
111
|
+
warnings: config.warnings
|
|
97
112
|
};
|
|
98
113
|
}
|
|
99
114
|
function brief(r) {
|
|
@@ -106,12 +121,24 @@ function brief(r) {
|
|
|
106
121
|
`repo: ${r.repoRoot}`,
|
|
107
122
|
`model: ${r.model} via ${r.endpoint}`,
|
|
108
123
|
`key: ${r.apiKey}${r.replay ? " \xB7 SYSTEM1_REPLAY forces replay" : ""}`,
|
|
109
|
-
`egress consent: ${c.granted ? `granted ${c.at ?? ""}`.trim() : "not granted
|
|
124
|
+
`egress consent: ${c.granted ? `granted ${c.at ?? ""}`.trim() : "not granted (the user grants it; see `decide doctor`)"}`,
|
|
110
125
|
`excludes: ${r.egress.defaultExcludes} default${r.egress.exclude.length ? ` + ${r.egress.exclude.join(", ")}` : ""}`,
|
|
111
|
-
`budget: ${r.budget.maxCalls} calls / $${r.budget.maxUsd} per request \xB7 concurrency ${r.concurrency}`,
|
|
112
|
-
|
|
126
|
+
`budget: ${r.budget.maxCalls} calls / $${r.budget.maxUsd} per request \xB7 concurrency ${r.concurrency} \xB7 timeout ${r.timeoutMs} ms`,
|
|
127
|
+
...r.profiles.length ? [`profiles: ${r.profiles.map((p) => p.id).join(", ")}`] : [],
|
|
128
|
+
`route: ${routeLine(r.route)}`,
|
|
129
|
+
`session: ${r.session ? `${r.session} (${r.sessionOrigin === "env" ? "SYSTEM1_SESSION" : `detected from ${r.sessionOrigin}`})` : "none"}`,
|
|
130
|
+
...r.warnings.length ? [`ignored: ${r.warnings.join("; ")}`] : []
|
|
113
131
|
].join("\n");
|
|
114
132
|
}
|
|
133
|
+
function routeLine(route) {
|
|
134
|
+
if (!route.enabled) return "off";
|
|
135
|
+
try {
|
|
136
|
+
const names = activeTriggers(route).map((t) => t.name);
|
|
137
|
+
return `on \xB7 ${names.join(", ") || "no triggers"}`;
|
|
138
|
+
} catch (error) {
|
|
139
|
+
return `invalid (${error instanceof Error ? error.message : String(error)})`;
|
|
140
|
+
}
|
|
141
|
+
}
|
|
115
142
|
export {
|
|
116
143
|
CONFIG_OPTIONS,
|
|
117
144
|
runConfigCommand
|
|
@@ -6,17 +6,17 @@ import {
|
|
|
6
6
|
import {
|
|
7
7
|
buildInput,
|
|
8
8
|
parseDecideFlags
|
|
9
|
-
} from "./chunk-
|
|
9
|
+
} from "./chunk-BGL272OK.mjs";
|
|
10
10
|
import {
|
|
11
11
|
createContext,
|
|
12
12
|
runAsk,
|
|
13
13
|
runMany
|
|
14
|
-
} from "./chunk-
|
|
14
|
+
} from "./chunk-5TUBFH7M.mjs";
|
|
15
15
|
import {
|
|
16
16
|
DecisionsError,
|
|
17
17
|
ENVELOPE_VERSION,
|
|
18
18
|
emit
|
|
19
|
-
} from "./chunk-
|
|
19
|
+
} from "./chunk-4ZZ3ZSJN.mjs";
|
|
20
20
|
|
|
21
21
|
// src/commands/decide.ts
|
|
22
22
|
import { readFileSync } from "node:fs";
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { createRequire as __decideRequire } from "node:module"; const require = __decideRequire(import.meta.url);
|
|
2
2
|
import {
|
|
3
3
|
runDoctor
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-5TUBFH7M.mjs";
|
|
5
5
|
import {
|
|
6
6
|
emit
|
|
7
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-4ZZ3ZSJN.mjs";
|
|
8
8
|
|
|
9
9
|
// src/commands/doctor.ts
|
|
10
10
|
import { execFile } from "node:child_process";
|
|
@@ -1,19 +1,22 @@
|
|
|
1
1
|
import { createRequire as __decideRequire } from "node:module"; const require = __decideRequire(import.meta.url);
|
|
2
2
|
import {
|
|
3
3
|
typedParse
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-BGL272OK.mjs";
|
|
5
5
|
import {
|
|
6
6
|
TOOL_SCHEMAS,
|
|
7
7
|
createContext,
|
|
8
|
+
loadConfig,
|
|
8
9
|
ping,
|
|
10
|
+
probeUrl,
|
|
9
11
|
resolveConnection,
|
|
10
12
|
runUsage
|
|
11
|
-
} from "./chunk-
|
|
13
|
+
} from "./chunk-5TUBFH7M.mjs";
|
|
12
14
|
import {
|
|
13
15
|
DecisionsError,
|
|
14
16
|
EXIT,
|
|
15
|
-
emit
|
|
16
|
-
|
|
17
|
+
emit,
|
|
18
|
+
isDecisionsError
|
|
19
|
+
} from "./chunk-4ZZ3ZSJN.mjs";
|
|
17
20
|
|
|
18
21
|
// src/commands/misc.ts
|
|
19
22
|
function runSchemaCommand(argv, io, format) {
|
|
@@ -55,7 +58,20 @@ async function runPingCommand(io, format) {
|
|
|
55
58
|
"ping",
|
|
56
59
|
format,
|
|
57
60
|
async () => {
|
|
58
|
-
const
|
|
61
|
+
const { config, configError } = connection(io);
|
|
62
|
+
try {
|
|
63
|
+
probeUrl(config);
|
|
64
|
+
} catch {
|
|
65
|
+
throw new DecisionsError(
|
|
66
|
+
"config-error",
|
|
67
|
+
`endpoint ${config.endpoint} is not a URL: correct SYSTEM1_ENDPOINT or \`endpoint\` in the config file`,
|
|
68
|
+
{ endpoint: config.endpoint }
|
|
69
|
+
);
|
|
70
|
+
}
|
|
71
|
+
const result = {
|
|
72
|
+
...await ping(config, io.fetch ? { fetch: io.fetch } : {}),
|
|
73
|
+
...configError ? { configError } : {}
|
|
74
|
+
};
|
|
59
75
|
failed = !result.ok;
|
|
60
76
|
if (!result.ok && format !== "brief") {
|
|
61
77
|
throw new DecisionsError("provider-unreachable", result.error ?? "unreachable", {
|
|
@@ -67,11 +83,28 @@ async function runPingCommand(io, format) {
|
|
|
67
83
|
(r, f) => {
|
|
68
84
|
if (f !== "brief") return void 0;
|
|
69
85
|
const key = r.keyPresent ? "key: present" : "key: absent (replay only)";
|
|
70
|
-
|
|
86
|
+
const line = r.ok ? `decide ping: ok \u2014 ${r.model} reachable in ${r.latencyMs} ms (${key})` : `decide ping: FAILED \u2014 ${r.probe}: ${r.error} (${key})`;
|
|
87
|
+
return r.configError ? `${line}
|
|
88
|
+
config not loaded, so this used the environment only: ${r.configError}` : line;
|
|
71
89
|
}
|
|
72
90
|
);
|
|
73
91
|
return failed ? EXIT.providerError : code;
|
|
74
92
|
}
|
|
93
|
+
function connection(io) {
|
|
94
|
+
try {
|
|
95
|
+
const config = loadConfig({
|
|
96
|
+
cwd: io.cwd ?? process.cwd(),
|
|
97
|
+
env: io.env,
|
|
98
|
+
...io.home ? { home: io.home } : {}
|
|
99
|
+
});
|
|
100
|
+
const { endpoint, model, apiKey, replay } = config;
|
|
101
|
+
return { config: { endpoint, model, apiKey, replay } };
|
|
102
|
+
} catch (error) {
|
|
103
|
+
if (isDecisionsError(error) && error.code === "config-error")
|
|
104
|
+
return { config: resolveConnection(io.env), configError: error.message };
|
|
105
|
+
throw error;
|
|
106
|
+
}
|
|
107
|
+
}
|
|
75
108
|
export {
|
|
76
109
|
USAGE_OPTIONS,
|
|
77
110
|
runPingCommand,
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
import { createRequire as __decideRequire } from "node:module"; const require = __decideRequire(import.meta.url);
|
|
2
2
|
import {
|
|
3
3
|
typedParse
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-BGL272OK.mjs";
|
|
5
5
|
import {
|
|
6
6
|
runRoute
|
|
7
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-5TUBFH7M.mjs";
|
|
8
8
|
import {
|
|
9
9
|
DecisionsError,
|
|
10
10
|
emit
|
|
11
|
-
} from "./chunk-
|
|
11
|
+
} from "./chunk-4ZZ3ZSJN.mjs";
|
|
12
12
|
|
|
13
13
|
// src/commands/route.ts
|
|
14
14
|
import { readFileSync } from "node:fs";
|
|
@@ -4,7 +4,7 @@ import {
|
|
|
4
4
|
} from "./chunk-5LVOFZF3.mjs";
|
|
5
5
|
import {
|
|
6
6
|
typedParse
|
|
7
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-BGL272OK.mjs";
|
|
8
8
|
import {
|
|
9
9
|
assertExamples,
|
|
10
10
|
createContext,
|
|
@@ -12,11 +12,12 @@ import {
|
|
|
12
12
|
listSpecs,
|
|
13
13
|
loadSpec,
|
|
14
14
|
runSpecCheck
|
|
15
|
-
} from "./chunk-
|
|
15
|
+
} from "./chunk-5TUBFH7M.mjs";
|
|
16
16
|
import {
|
|
17
17
|
DecisionsError,
|
|
18
|
+
EXIT,
|
|
18
19
|
emit
|
|
19
|
-
} from "./chunk-
|
|
20
|
+
} from "./chunk-4ZZ3ZSJN.mjs";
|
|
20
21
|
|
|
21
22
|
// src/commands/spec.ts
|
|
22
23
|
function runSpecCommand(argv, io, format) {
|
|
@@ -70,13 +71,7 @@ function runSpecCommand(argv, io, format) {
|
|
|
70
71
|
(r, f) => f === "brief" ? `valid: ${r.valid.join(", ") || "(none)"}` : void 0
|
|
71
72
|
);
|
|
72
73
|
case "check":
|
|
73
|
-
return
|
|
74
|
-
io,
|
|
75
|
-
"spec",
|
|
76
|
-
format,
|
|
77
|
-
() => runSpecCheck(ctx(), checkInput(argv.slice(1))),
|
|
78
|
-
(r, f) => f === "brief" ? briefSpecCheck(r) : void 0
|
|
79
|
-
);
|
|
74
|
+
return check(argv.slice(1), io, format, ctx);
|
|
80
75
|
default:
|
|
81
76
|
return emit(io, "spec", format, () => {
|
|
82
77
|
throw new DecisionsError(
|
|
@@ -86,13 +81,28 @@ function runSpecCommand(argv, io, format) {
|
|
|
86
81
|
});
|
|
87
82
|
}
|
|
88
83
|
}
|
|
84
|
+
async function check(argv, io, format, ctx) {
|
|
85
|
+
let failed = false;
|
|
86
|
+
const code = await emit(
|
|
87
|
+
io,
|
|
88
|
+
"spec",
|
|
89
|
+
format,
|
|
90
|
+
async () => {
|
|
91
|
+
const result = await runSpecCheck(ctx(), checkInput(argv));
|
|
92
|
+
failed = !result.passed;
|
|
93
|
+
return result;
|
|
94
|
+
},
|
|
95
|
+
(r, f) => f === "brief" ? briefSpecCheck(r) : void 0
|
|
96
|
+
);
|
|
97
|
+
return code === EXIT.ok && failed && parse(argv).values.strict ? EXIT.checkFailed : code;
|
|
98
|
+
}
|
|
89
99
|
function checkInput(argv) {
|
|
90
100
|
const { values, positionals } = parse(argv);
|
|
91
101
|
const [spec, extra] = positionals;
|
|
92
102
|
if (!spec || extra !== void 0) {
|
|
93
103
|
throw new DecisionsError(
|
|
94
104
|
"invalid-request",
|
|
95
|
-
"Usage: decide spec check <name|path> [--live] [--confirm] [--model <id>]"
|
|
105
|
+
"Usage: decide spec check <name|path> [--live] [--confirm] [--model <id>] [--strict]"
|
|
96
106
|
);
|
|
97
107
|
}
|
|
98
108
|
if (values.live && values.replay) {
|
|
@@ -109,7 +119,8 @@ var SPEC_OPTIONS = {
|
|
|
109
119
|
live: { type: "boolean" },
|
|
110
120
|
replay: { type: "boolean" },
|
|
111
121
|
confirm: { type: "boolean" },
|
|
112
|
-
model: { type: "string" }
|
|
122
|
+
model: { type: "string" },
|
|
123
|
+
strict: { type: "boolean" }
|
|
113
124
|
};
|
|
114
125
|
function parse(argv) {
|
|
115
126
|
return typedParse({
|
package/dist/bundle/decide.mjs
CHANGED