@garygentry/system1 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +14 -0
- package/THIRD-PARTY-NOTICES.md +116 -0
- package/dist/bundle/chunks/bin-IIUCANF7.mjs +141 -0
- package/dist/bundle/chunks/chunk-5LVOFZF3.mjs +130 -0
- package/dist/bundle/chunks/chunk-7LVHD6A5.mjs +165 -0
- package/dist/bundle/chunks/chunk-A7ODZFMY.mjs +197 -0
- package/dist/bundle/chunks/chunk-V7OTO67I.mjs +20583 -0
- package/dist/bundle/chunks/config-QR35VKVT.mjs +116 -0
- package/dist/bundle/chunks/decide-PW7REJ6Y.mjs +77 -0
- package/dist/bundle/chunks/doctor-HAT6XVTW.mjs +61 -0
- package/dist/bundle/chunks/misc-6VZKJEN4.mjs +78 -0
- package/dist/bundle/chunks/spec-Z2LZJ5EZ.mjs +123 -0
- package/dist/bundle/decide.mjs +7 -0
- package/package.json +47 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Gary Gentry
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
# @garygentry/system1
|
|
2
|
+
|
|
3
|
+
The `decide` CLI: typed, calibrated decisions for coding agents, hooks and CI.
|
|
4
|
+
|
|
5
|
+
```sh
|
|
6
|
+
npm i -g @garygentry/system1
|
|
7
|
+
decide doctor --format brief
|
|
8
|
+
```
|
|
9
|
+
|
|
10
|
+
`decide` sends a closed judgement (yes/no, pick one of N, rate on a scale) to a decision model and returns a typed, calibrated answer in about 300 ms for about $0.00003 an item. It reads and splits the content itself, excludes secret-shaped files, scrubs secrets from what it sends, and never sends anything until the repo has given consent with `decide config egress allow`.
|
|
11
|
+
|
|
12
|
+
Full documentation, the skills for Claude Code, Codex and Pi, and what gets sent: **https://github.com/garygentry/system1**
|
|
13
|
+
|
|
14
|
+
MIT
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
# Third-party notices
|
|
2
|
+
|
|
3
|
+
The `decide` CLI ships as a single bundle with these packages compiled into
|
|
4
|
+
it. Their licences and copyright notices are reproduced in full, as those
|
|
5
|
+
licences require. Generated by `node tools/notices.mjs`; do not edit.
|
|
6
|
+
|
|
7
|
+
- picomatch 4.0.7 (MIT)
|
|
8
|
+
- tinyglobby 0.2.17 (MIT)
|
|
9
|
+
- typebox 1.3.34 (MIT)
|
|
10
|
+
- yaml 2.9.1 (ISC)
|
|
11
|
+
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
## picomatch 4.0.7
|
|
15
|
+
|
|
16
|
+
```
|
|
17
|
+
The MIT License (MIT)
|
|
18
|
+
|
|
19
|
+
Copyright (c) 2017-present, Jon Schlinkert.
|
|
20
|
+
|
|
21
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
22
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
23
|
+
in the Software without restriction, including without limitation the rights
|
|
24
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
25
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
26
|
+
furnished to do so, subject to the following conditions:
|
|
27
|
+
|
|
28
|
+
The above copyright notice and this permission notice shall be included in
|
|
29
|
+
all copies or substantial portions of the Software.
|
|
30
|
+
|
|
31
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
32
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
33
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
34
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
35
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
36
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
37
|
+
THE SOFTWARE.
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
---
|
|
41
|
+
|
|
42
|
+
## tinyglobby 0.2.17
|
|
43
|
+
|
|
44
|
+
```
|
|
45
|
+
MIT License
|
|
46
|
+
|
|
47
|
+
Copyright (c) 2024 Madeline Gurriarán
|
|
48
|
+
|
|
49
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
50
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
51
|
+
in the Software without restriction, including without limitation the rights
|
|
52
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
53
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
54
|
+
furnished to do so, subject to the following conditions:
|
|
55
|
+
|
|
56
|
+
The above copyright notice and this permission notice shall be included in all
|
|
57
|
+
copies or substantial portions of the Software.
|
|
58
|
+
|
|
59
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
60
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
61
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
62
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
63
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
64
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
65
|
+
SOFTWARE.
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
---
|
|
69
|
+
|
|
70
|
+
## typebox 1.3.34
|
|
71
|
+
|
|
72
|
+
```
|
|
73
|
+
TypeBox
|
|
74
|
+
|
|
75
|
+
The MIT License (MIT)
|
|
76
|
+
|
|
77
|
+
Copyright (c) 2017-2026 Haydn Paterson
|
|
78
|
+
|
|
79
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
80
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
81
|
+
in the Software without restriction, including without limitation the rights
|
|
82
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
83
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
84
|
+
furnished to do so, subject to the following conditions:
|
|
85
|
+
|
|
86
|
+
The above copyright notice and this permission notice shall be included in
|
|
87
|
+
all copies or substantial portions of the Software.
|
|
88
|
+
|
|
89
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
90
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
91
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
92
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
93
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
94
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
95
|
+
THE SOFTWARE.
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
---
|
|
99
|
+
|
|
100
|
+
## yaml 2.9.1
|
|
101
|
+
|
|
102
|
+
```
|
|
103
|
+
Copyright Eemeli Aro <eemeli@gmail.com>
|
|
104
|
+
|
|
105
|
+
Permission to use, copy, modify, and/or distribute this software for any purpose
|
|
106
|
+
with or without fee is hereby granted, provided that the above copyright notice
|
|
107
|
+
and this permission notice appear in all copies.
|
|
108
|
+
|
|
109
|
+
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
|
|
110
|
+
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
|
111
|
+
FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
|
|
112
|
+
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
|
|
113
|
+
OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
|
|
114
|
+
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
|
|
115
|
+
THIS SOFTWARE.
|
|
116
|
+
```
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { createRequire as __decideRequire } from "node:module"; const require = __decideRequire(import.meta.url);
|
|
3
|
+
import {
|
|
4
|
+
DecisionsError,
|
|
5
|
+
EXIT,
|
|
6
|
+
VERSION,
|
|
7
|
+
emit,
|
|
8
|
+
extractFormat
|
|
9
|
+
} from "./chunk-7LVHD6A5.mjs";
|
|
10
|
+
|
|
11
|
+
// src/bin.ts
|
|
12
|
+
import { readFileSync as readFileSync2 } from "node:fs";
|
|
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
|
+
}
|
|
41
|
+
|
|
42
|
+
// src/main.ts
|
|
43
|
+
var HELP = `decide ${VERSION} \u2014 typed, calibrated decisions for coding agents
|
|
44
|
+
|
|
45
|
+
Usage: decide <command> [options] [--format json|jsonl|brief]
|
|
46
|
+
|
|
47
|
+
Commands:
|
|
48
|
+
ask One state, one question set, one call
|
|
49
|
+
many One question set over many items (fan-out), filtered to what matters
|
|
50
|
+
usage Measured spend from the ledger (--session, --since)
|
|
51
|
+
config Show resolved config; \`config egress allow|deny|status\` for consent
|
|
52
|
+
spec list | show <name> | validate [name|path] | check <name> [--live]
|
|
53
|
+
schema Print the JSON Schema of a tool's input (ask, many, usage, spec-check)
|
|
54
|
+
ping Check the endpoint is reachable (no key, no spend)
|
|
55
|
+
doctor Check decide works from this shell; prints the fix for each problem
|
|
56
|
+
version Print the version
|
|
57
|
+
|
|
58
|
+
Questions: --spec <name|path> | --question name:noul:<text>
|
|
59
|
+
--question name:choice:<text>:key=desc|key=desc|none=None of these
|
|
60
|
+
--question name:score:<text>:level 0|level 1|level 2
|
|
61
|
+
--questions <file|-|inline YAML/JSON> (a question set; richer than --question)
|
|
62
|
+
--input <file|-> (full tool input as JSON; flags override it)
|
|
63
|
+
Sources: --glob <pattern>\u2026 --file <path[:L1-L2]>\u2026 --jsonl <path>
|
|
64
|
+
--diff <range> [--staged] --text <text> --stdin
|
|
65
|
+
Split: --split file|hunk|row|join|lines:N[/overlap] (default: file; join = one state)
|
|
66
|
+
Project: --keep 'relevant>=0.7'\u2026 --sort relevant:desc --limit N --fields a,b
|
|
67
|
+
--allow-outside (read files that resolve outside the repo)
|
|
68
|
+
Run: --dry-run --confirm --record | --replay | --live --model <id> --concurrency N
|
|
69
|
+
|
|
70
|
+
Output is one JSON envelope by default: {v, ok, command, result | error}.
|
|
71
|
+
Exit codes: 0 ok \xB7 1 failure \xB7 2 usage \xB7 3 egress refused \xB7 4 budget guard
|
|
72
|
+
5 provider error \xB7 6 replay miss
|
|
73
|
+
`;
|
|
74
|
+
var DEFAULT_FORMAT = "json";
|
|
75
|
+
async function main(argv, io) {
|
|
76
|
+
const [command, ...args] = argv;
|
|
77
|
+
let format;
|
|
78
|
+
let rest;
|
|
79
|
+
let explicitFormat;
|
|
80
|
+
try {
|
|
81
|
+
;
|
|
82
|
+
({ format, rest, explicit: explicitFormat } = extractFormat(args, DEFAULT_FORMAT));
|
|
83
|
+
} catch (error) {
|
|
84
|
+
return emit(io, command ?? "decide", DEFAULT_FORMAT, () => {
|
|
85
|
+
throw error;
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
if (command === void 0 || command === "help" || command === "--help" || command === "-h" || rest.includes("--help")) {
|
|
89
|
+
io.out(HELP);
|
|
90
|
+
return EXIT.ok;
|
|
91
|
+
}
|
|
92
|
+
switch (command) {
|
|
93
|
+
case "ask":
|
|
94
|
+
return (await import("./decide-PW7REJ6Y.mjs")).runAskCommand(rest, io, format);
|
|
95
|
+
case "many":
|
|
96
|
+
return (await import("./decide-PW7REJ6Y.mjs")).runManyCommand(rest, io, format);
|
|
97
|
+
case "usage":
|
|
98
|
+
return (await import("./misc-6VZKJEN4.mjs")).runUsageCommand(rest, io, format);
|
|
99
|
+
case "config":
|
|
100
|
+
return (await import("./config-QR35VKVT.mjs")).runConfigCommand(rest, io, format);
|
|
101
|
+
case "spec":
|
|
102
|
+
return (await import("./spec-Z2LZJ5EZ.mjs")).runSpecCommand(rest, io, format);
|
|
103
|
+
case "schema":
|
|
104
|
+
return (await import("./misc-6VZKJEN4.mjs")).runSchemaCommand(rest, io, format);
|
|
105
|
+
case "ping":
|
|
106
|
+
return (await import("./misc-6VZKJEN4.mjs")).runPingCommand(io, format);
|
|
107
|
+
case "doctor":
|
|
108
|
+
return (await import("./doctor-HAT6XVTW.mjs")).runDoctorCommand(io, format);
|
|
109
|
+
case "version":
|
|
110
|
+
case "--version":
|
|
111
|
+
case "-v":
|
|
112
|
+
return emit(
|
|
113
|
+
io,
|
|
114
|
+
"version",
|
|
115
|
+
// Bare `decide version` prints the number; an explicit --format wins.
|
|
116
|
+
explicitFormat ? format : "brief",
|
|
117
|
+
() => ({ version: VERSION }),
|
|
118
|
+
(r, f) => f === "json" ? void 0 : r.version
|
|
119
|
+
);
|
|
120
|
+
default:
|
|
121
|
+
return emit(io, command, format, () => {
|
|
122
|
+
throw new DecisionsError(
|
|
123
|
+
"invalid-request",
|
|
124
|
+
`unknown command "${command}". Run \`decide help\`.`
|
|
125
|
+
);
|
|
126
|
+
});
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
// src/bin.ts
|
|
131
|
+
var line = (stream) => (text) => stream.write(text.endsWith("\n") ? text : `${text}
|
|
132
|
+
`);
|
|
133
|
+
process.exitCode = await main(process.argv.slice(2), {
|
|
134
|
+
out: line(process.stdout),
|
|
135
|
+
err: line(process.stderr),
|
|
136
|
+
env: process.env,
|
|
137
|
+
cwd: process.cwd(),
|
|
138
|
+
readStdin: () => readFileSync2(0, "utf8"),
|
|
139
|
+
interactive: Boolean(process.stdin.isTTY && process.stdout.isTTY),
|
|
140
|
+
...bundledSpecsDir() ? { bundledSpecs: bundledSpecsDir() } : {}
|
|
141
|
+
});
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
import { createRequire as __decideRequire } from "node:module"; const require = __decideRequire(import.meta.url);
|
|
2
|
+
|
|
3
|
+
// src/format.ts
|
|
4
|
+
function briefAnswer(name, answer, undecided) {
|
|
5
|
+
const flag = undecided ? " UNDECIDED" : "";
|
|
6
|
+
switch (answer.type) {
|
|
7
|
+
case "noul":
|
|
8
|
+
return `${name}=${fix(answer.noul)}${flag}`;
|
|
9
|
+
case "choice":
|
|
10
|
+
return `${name}=${answer.choice}(${fix(answer.confidence)})${flag}`;
|
|
11
|
+
case "score": {
|
|
12
|
+
const top = answer.legend ? Object.keys(answer.legend).length - 1 : void 0;
|
|
13
|
+
return `${name}=${fix(answer.score)}${top !== void 0 ? `/${top}` : ""}(${fix(answer.confidence)})${flag}`;
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
function briefAnswers(answers, undecided = []) {
|
|
18
|
+
return Object.entries(answers).map(([name, a]) => briefAnswer(name, a, undecided.includes(name))).join(" ");
|
|
19
|
+
}
|
|
20
|
+
function where(row) {
|
|
21
|
+
return row.id;
|
|
22
|
+
}
|
|
23
|
+
function quoted(row) {
|
|
24
|
+
return row.excerpt ? ` "${row.excerpt}"` : "";
|
|
25
|
+
}
|
|
26
|
+
function briefMany(r) {
|
|
27
|
+
const lines = [];
|
|
28
|
+
if (r.dryRun) {
|
|
29
|
+
lines.push(
|
|
30
|
+
`decide many (dry run): would send ${r.counts.items} item(s) to ${r.model} \xB7 ${projected(r.projection)} \xB7 no calls made`
|
|
31
|
+
);
|
|
32
|
+
if (r.sampleIds?.length) lines.push(`first: ${r.sampleIds.join(", ")}`);
|
|
33
|
+
} else {
|
|
34
|
+
const c = r.counts;
|
|
35
|
+
lines.push(
|
|
36
|
+
`decide many: ${c.kept}${c.keptTotal > c.kept ? ` (of ${c.keptTotal})` : ""} kept of ${c.items} \xB7 ${c.undecided} undecided \xB7 ${c.dropped} dropped${c.failed ? ` \xB7 ${c.failed} FAILED` : ""} \xB7 ${r.source} ${r.model} \xB7 ${measured(r.usage)} \xB7 ${seconds(r.wallClockMs)}`
|
|
37
|
+
);
|
|
38
|
+
if (r.kept.length) {
|
|
39
|
+
lines.push("kept:");
|
|
40
|
+
for (const row of r.kept)
|
|
41
|
+
lines.push(` ${where(row)} ${briefAnswers(row.answers, row.undecided)}${quoted(row)}`);
|
|
42
|
+
}
|
|
43
|
+
if (r.undecided.length) {
|
|
44
|
+
lines.push("undecided (too flat to judge; read these yourself):");
|
|
45
|
+
for (const row of r.undecided)
|
|
46
|
+
lines.push(` ${where(row)} ${briefAnswers(row.answers, row.questions)}${quoted(row)}`);
|
|
47
|
+
}
|
|
48
|
+
if (r.failed.length) {
|
|
49
|
+
lines.push("failed:");
|
|
50
|
+
for (const f of r.failed) lines.push(` ${f.id} ${f.code}: ${firstLine(f.message)}`);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
lines.push(...withheld(r.skipped, r.redactions));
|
|
54
|
+
return lines.join("\n");
|
|
55
|
+
}
|
|
56
|
+
function briefAsk(r) {
|
|
57
|
+
const lines = [
|
|
58
|
+
`decide ask: ${r.id} \xB7 ${r.source} ${r.servedBy} \xB7 ${r.latencyMs} ms \xB7 ${measured(r.usage)}`,
|
|
59
|
+
...Object.entries(r.answers).map(
|
|
60
|
+
([name, a]) => ` ${briefAnswer(name, a, r.undecided.includes(name))}`
|
|
61
|
+
)
|
|
62
|
+
];
|
|
63
|
+
if (r.verdict) lines.push(`verdict: ${r.verdict}`);
|
|
64
|
+
lines.push(...withheld(r.skipped, r.redactions));
|
|
65
|
+
return lines.join("\n");
|
|
66
|
+
}
|
|
67
|
+
function briefSpecCheck(r) {
|
|
68
|
+
const c = r.counts;
|
|
69
|
+
const parts = [`${c.pass} pass`, `${c.fail} fail`, `${c.undecided} undecided`];
|
|
70
|
+
if (c.captured) parts.push(`${c.captured} captured`);
|
|
71
|
+
if (c.withheld) parts.push(`${c.withheld} withheld`);
|
|
72
|
+
const lines = [
|
|
73
|
+
`decide spec check: ${r.spec} ${r.passed ? "PASSED" : "FAILED"} \xB7 ${parts.join(" \xB7 ")} \xB7 ${r.source} ${r.model} \xB7 ${measured(r.usage)}`
|
|
74
|
+
];
|
|
75
|
+
for (const e of r.examples) {
|
|
76
|
+
const label = e.status === "pass" ? "pass" : e.status.toUpperCase();
|
|
77
|
+
if (e.status === "withheld") {
|
|
78
|
+
lines.push(` ${label} ${e.id} ${e.reason ?? ""}`);
|
|
79
|
+
continue;
|
|
80
|
+
}
|
|
81
|
+
lines.push(` ${label} ${e.id} ${e.answers ? briefAnswers(e.answers, e.undecided) : ""}`);
|
|
82
|
+
for (const f of e.failures ?? []) lines.push(` expected ${f.question}: ${f.expected}`);
|
|
83
|
+
if (e.status !== "pass" && e.answers) {
|
|
84
|
+
for (const [name, a] of Object.entries(e.answers)) {
|
|
85
|
+
if (a.type !== "noul") lines.push(` ${name}: ${distribution(a.probabilities)}`);
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
lines.push(...withheld(r.skipped, { total: 0, items: 0 }));
|
|
90
|
+
return lines.join("\n");
|
|
91
|
+
}
|
|
92
|
+
function distribution(probabilities) {
|
|
93
|
+
return Object.entries(probabilities).sort((a, b) => b[1] - a[1]).map(([k, p]) => `${k} ${fix(p)}`).join(" \xB7 ");
|
|
94
|
+
}
|
|
95
|
+
function withheld(skipped, redactions) {
|
|
96
|
+
const lines = [];
|
|
97
|
+
if (skipped.total > 0) {
|
|
98
|
+
const reasons = Object.entries(skipped.byReason).map(([k, v]) => `${k} ${v}`).join(", ");
|
|
99
|
+
const excluded = skipped.sample.filter((s) => s.reason === "excluded").map((s) => s.path);
|
|
100
|
+
lines.push(
|
|
101
|
+
`withheld: ${skipped.total} (${reasons})${excluded.length ? ` e.g. ${excluded.join(", ")}` : ""}`
|
|
102
|
+
);
|
|
103
|
+
}
|
|
104
|
+
if (redactions.total > 0)
|
|
105
|
+
lines.push(
|
|
106
|
+
`redacted: ${redactions.total} secret(s) in ${redactions.items} item(s) before sending`
|
|
107
|
+
);
|
|
108
|
+
return lines;
|
|
109
|
+
}
|
|
110
|
+
function projected(p) {
|
|
111
|
+
return `projected $${p.projectedUsd.toFixed(6)} (~${p.estimatedInputTokens} tokens, price as of ${p.priceAsOf})`;
|
|
112
|
+
}
|
|
113
|
+
function measured(u) {
|
|
114
|
+
return u.reported === false ? `$${u.cost.toFixed(6)} measured (incomplete: the provider reported no usage for at least one call)` : `$${u.cost.toFixed(6)} measured`;
|
|
115
|
+
}
|
|
116
|
+
function seconds(ms) {
|
|
117
|
+
return ms < 1e3 ? `${ms} ms` : `${(ms / 1e3).toFixed(1)} s`;
|
|
118
|
+
}
|
|
119
|
+
function fix(n) {
|
|
120
|
+
return Number.isInteger(n) ? String(n) : n.toFixed(2);
|
|
121
|
+
}
|
|
122
|
+
function firstLine(text) {
|
|
123
|
+
return text.split("\n")[0] ?? text;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
export {
|
|
127
|
+
briefMany,
|
|
128
|
+
briefAsk,
|
|
129
|
+
briefSpecCheck
|
|
130
|
+
};
|
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
import { createRequire as __decideRequire } from "node:module"; const require = __decideRequire(import.meta.url);
|
|
2
|
+
var __create = Object.create;
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
7
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
|
|
9
|
+
get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
|
|
10
|
+
}) : x)(function(x) {
|
|
11
|
+
if (typeof require !== "undefined") return require.apply(this, arguments);
|
|
12
|
+
throw Error('Dynamic require of "' + x + '" is not supported');
|
|
13
|
+
});
|
|
14
|
+
var __commonJS = (cb, mod) => function __require2() {
|
|
15
|
+
try {
|
|
16
|
+
return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
|
|
17
|
+
} catch (e) {
|
|
18
|
+
throw mod = 0, e;
|
|
19
|
+
}
|
|
20
|
+
};
|
|
21
|
+
var __export = (target, all) => {
|
|
22
|
+
for (var name in all)
|
|
23
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
24
|
+
};
|
|
25
|
+
var __copyProps = (to, from, except, desc) => {
|
|
26
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
27
|
+
for (let key of __getOwnPropNames(from))
|
|
28
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
29
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
30
|
+
}
|
|
31
|
+
return to;
|
|
32
|
+
};
|
|
33
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
34
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
35
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
36
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
37
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
38
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
39
|
+
mod
|
|
40
|
+
));
|
|
41
|
+
|
|
42
|
+
// ../core/dist/errors.js
|
|
43
|
+
var DecisionsError = class extends Error {
|
|
44
|
+
code;
|
|
45
|
+
details;
|
|
46
|
+
constructor(code, message, details = {}) {
|
|
47
|
+
super(message);
|
|
48
|
+
this.code = code;
|
|
49
|
+
this.details = details;
|
|
50
|
+
this.name = "DecisionsError";
|
|
51
|
+
}
|
|
52
|
+
};
|
|
53
|
+
var ProviderError = class extends DecisionsError {
|
|
54
|
+
status;
|
|
55
|
+
constructor(code, message, status) {
|
|
56
|
+
super(code, message, status === void 0 ? {} : { status });
|
|
57
|
+
this.status = status;
|
|
58
|
+
this.name = "ProviderError";
|
|
59
|
+
}
|
|
60
|
+
};
|
|
61
|
+
function isDecisionsError(error) {
|
|
62
|
+
return error instanceof DecisionsError;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
// src/exit-codes.ts
|
|
66
|
+
var EXIT = {
|
|
67
|
+
ok: 0,
|
|
68
|
+
failure: 1,
|
|
69
|
+
usage: 2,
|
|
70
|
+
egressRefused: 3,
|
|
71
|
+
budgetGuard: 4,
|
|
72
|
+
providerError: 5,
|
|
73
|
+
replayMiss: 6
|
|
74
|
+
};
|
|
75
|
+
var BY_CODE = {
|
|
76
|
+
"invalid-request": EXIT.usage,
|
|
77
|
+
"state-too-large": EXIT.usage,
|
|
78
|
+
"unknown-model": EXIT.usage,
|
|
79
|
+
"config-error": EXIT.usage,
|
|
80
|
+
"source-error": EXIT.usage,
|
|
81
|
+
"no-key": EXIT.usage,
|
|
82
|
+
"egress-refused": EXIT.egressRefused,
|
|
83
|
+
"budget-exceeded": EXIT.budgetGuard,
|
|
84
|
+
"provider-unreachable": EXIT.providerError,
|
|
85
|
+
"provider-http": EXIT.providerError,
|
|
86
|
+
"malformed-response": EXIT.providerError,
|
|
87
|
+
"replay-miss": EXIT.replayMiss
|
|
88
|
+
};
|
|
89
|
+
function exitFor(code) {
|
|
90
|
+
return code === "error" ? EXIT.failure : BY_CODE[code];
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
// src/envelope.ts
|
|
94
|
+
var ENVELOPE_VERSION = 1;
|
|
95
|
+
var FORMATS = ["json", "jsonl", "brief"];
|
|
96
|
+
function ok(command, result) {
|
|
97
|
+
return { v: ENVELOPE_VERSION, ok: true, command, result };
|
|
98
|
+
}
|
|
99
|
+
function fail(command, code, message, details) {
|
|
100
|
+
return {
|
|
101
|
+
v: ENVELOPE_VERSION,
|
|
102
|
+
ok: false,
|
|
103
|
+
command,
|
|
104
|
+
error: { code, message, ...details && Object.keys(details).length ? { details } : {} }
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
// src/run.ts
|
|
109
|
+
async function emit(io, command, format, body, render = () => void 0) {
|
|
110
|
+
try {
|
|
111
|
+
const result = await body();
|
|
112
|
+
io.out(render(result, format) ?? JSON.stringify(ok(command, result)));
|
|
113
|
+
return EXIT.ok;
|
|
114
|
+
} catch (error) {
|
|
115
|
+
const code = isDecisionsError(error) ? error.code : "error";
|
|
116
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
117
|
+
const details = isDecisionsError(error) ? error.details : void 0;
|
|
118
|
+
io.out(
|
|
119
|
+
format === "brief" ? `decide ${command}: error ${code} \u2014 ${message}` : JSON.stringify(fail(command, code, message, details))
|
|
120
|
+
);
|
|
121
|
+
if (!isDecisionsError(error) && error instanceof Error && io.env.SYSTEM1_DEBUG)
|
|
122
|
+
io.err(error.stack ?? "");
|
|
123
|
+
return exitFor(code);
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
function extractFormat(argv, fallback) {
|
|
127
|
+
const rest = [];
|
|
128
|
+
let format;
|
|
129
|
+
for (let i = 0; i < argv.length; i += 1) {
|
|
130
|
+
const arg = argv[i];
|
|
131
|
+
if (arg === "--format") {
|
|
132
|
+
format = argv[i + 1];
|
|
133
|
+
i += 1;
|
|
134
|
+
} else if (arg.startsWith("--format=")) {
|
|
135
|
+
format = arg.slice("--format=".length);
|
|
136
|
+
} else {
|
|
137
|
+
rest.push(arg);
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
if (format === void 0) return { format: fallback, rest, explicit: false };
|
|
141
|
+
if (!FORMATS.includes(format)) {
|
|
142
|
+
throw new DecisionsError("invalid-request", `--format must be one of ${FORMATS.join(", ")}`);
|
|
143
|
+
}
|
|
144
|
+
return { format, rest, explicit: true };
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
// ../core/dist/version.js
|
|
148
|
+
var VERSION = "0.1.0";
|
|
149
|
+
var CLI_PACKAGE = "@garygentry/system1";
|
|
150
|
+
|
|
151
|
+
export {
|
|
152
|
+
__require,
|
|
153
|
+
__commonJS,
|
|
154
|
+
__export,
|
|
155
|
+
__toESM,
|
|
156
|
+
DecisionsError,
|
|
157
|
+
ProviderError,
|
|
158
|
+
isDecisionsError,
|
|
159
|
+
VERSION,
|
|
160
|
+
CLI_PACKAGE,
|
|
161
|
+
EXIT,
|
|
162
|
+
ENVELOPE_VERSION,
|
|
163
|
+
emit,
|
|
164
|
+
extractFormat
|
|
165
|
+
};
|