@bobobowis/jev-kit 0.0.0-stage → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (107) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +311 -2
  3. package/dist/capabilities.d.ts +33 -0
  4. package/dist/capabilities.js +81 -0
  5. package/dist/cli/ask.d.ts +9 -0
  6. package/dist/cli/ask.js +210 -0
  7. package/dist/cli/common.d.ts +38 -0
  8. package/dist/cli/common.js +40 -0
  9. package/dist/cli/hook.d.ts +3 -0
  10. package/dist/cli/hook.js +85 -0
  11. package/dist/cli/index.d.ts +2 -0
  12. package/dist/cli/index.js +21 -0
  13. package/dist/cli/main.d.ts +8 -0
  14. package/dist/cli/main.js +41 -0
  15. package/dist/cli/mcp.d.ts +3 -0
  16. package/dist/cli/mcp.js +47 -0
  17. package/dist/cli/setup.d.ts +3 -0
  18. package/dist/cli/setup.js +84 -0
  19. package/dist/compact/compact-on-demand.d.ts +22 -0
  20. package/dist/compact/compact-on-demand.js +29 -0
  21. package/dist/compact/evaluate.d.ts +36 -0
  22. package/dist/compact/evaluate.js +31 -0
  23. package/dist/compact/index.d.ts +7 -0
  24. package/dist/compact/index.js +7 -0
  25. package/dist/compact/pick-cut-point.d.ts +18 -0
  26. package/dist/compact/pick-cut-point.js +29 -0
  27. package/dist/compact/should-compact.d.ts +57 -0
  28. package/dist/compact/should-compact.js +87 -0
  29. package/dist/core/client.d.ts +93 -0
  30. package/dist/core/client.js +295 -0
  31. package/dist/core/helpers.d.ts +14 -0
  32. package/dist/core/helpers.js +9 -0
  33. package/dist/core/mock.d.ts +20 -0
  34. package/dist/core/mock.js +132 -0
  35. package/dist/core/types.d.ts +102 -0
  36. package/dist/core/types.js +82 -0
  37. package/dist/events/index.d.ts +44 -0
  38. package/dist/events/index.js +77 -0
  39. package/dist/files/ask-file-bool.d.ts +12 -0
  40. package/dist/files/ask-file-bool.js +15 -0
  41. package/dist/files/ask-file-choice.d.ts +10 -0
  42. package/dist/files/ask-file-choice.js +17 -0
  43. package/dist/files/ask-file-score.d.ts +12 -0
  44. package/dist/files/ask-file-score.js +15 -0
  45. package/dist/files/ask-files.d.ts +23 -0
  46. package/dist/files/ask-files.js +56 -0
  47. package/dist/files/ask.d.ts +12 -0
  48. package/dist/files/ask.js +28 -0
  49. package/dist/files/assemble.d.ts +52 -0
  50. package/dist/files/assemble.js +129 -0
  51. package/dist/files/decide.d.ts +10 -0
  52. package/dist/files/decide.js +1 -0
  53. package/dist/files/index.d.ts +14 -0
  54. package/dist/files/index.js +14 -0
  55. package/dist/files/pick-first.d.ts +16 -0
  56. package/dist/files/pick-first.js +24 -0
  57. package/dist/files/prune.d.ts +13 -0
  58. package/dist/files/prune.js +87 -0
  59. package/dist/files/read-state.d.ts +17 -0
  60. package/dist/files/read-state.js +47 -0
  61. package/dist/guards/bash-gate.d.ts +65 -0
  62. package/dist/guards/bash-gate.js +78 -0
  63. package/dist/guards/index.d.ts +7 -0
  64. package/dist/guards/index.js +7 -0
  65. package/dist/guards/mcp-gate.d.ts +23 -0
  66. package/dist/guards/mcp-gate.js +52 -0
  67. package/dist/guards/result-screen.d.ts +20 -0
  68. package/dist/guards/result-screen.js +31 -0
  69. package/dist/guards/write-gate.d.ts +18 -0
  70. package/dist/guards/write-gate.js +44 -0
  71. package/dist/hooks/handle.d.ts +76 -0
  72. package/dist/hooks/handle.js +61 -0
  73. package/dist/hooks/harness.d.ts +45 -0
  74. package/dist/hooks/harness.js +124 -0
  75. package/dist/hooks/index.d.ts +7 -0
  76. package/dist/hooks/index.js +7 -0
  77. package/dist/hooks/state.d.ts +8 -0
  78. package/dist/hooks/state.js +25 -0
  79. package/dist/hooks/transcript.d.ts +8 -0
  80. package/dist/hooks/transcript.js +52 -0
  81. package/dist/index.d.ts +8 -0
  82. package/dist/index.js +8 -0
  83. package/dist/ledger.d.ts +22 -0
  84. package/dist/ledger.js +26 -0
  85. package/dist/mcp/server.d.ts +28 -0
  86. package/dist/mcp/server.js +124 -0
  87. package/dist/policy/index.d.ts +17 -0
  88. package/dist/policy/index.js +30 -0
  89. package/dist/setup/index.d.ts +76 -0
  90. package/dist/setup/index.js +221 -0
  91. package/dist/tools/ask-jev.d.ts +7 -0
  92. package/dist/tools/ask-jev.js +42 -0
  93. package/dist/tools/compact-tool.d.ts +2 -0
  94. package/dist/tools/compact-tool.js +33 -0
  95. package/dist/tools/description.d.ts +5 -0
  96. package/dist/tools/description.js +20 -0
  97. package/dist/tools/file-tools.d.ts +7 -0
  98. package/dist/tools/file-tools.js +127 -0
  99. package/dist/tools/index.d.ts +10 -0
  100. package/dist/tools/index.js +10 -0
  101. package/dist/tools/run-command.d.ts +7 -0
  102. package/dist/tools/run-command.js +27 -0
  103. package/dist/tools/sets.d.ts +9 -0
  104. package/dist/tools/sets.js +32 -0
  105. package/dist/tools/types.d.ts +51 -0
  106. package/dist/tools/types.js +4 -0
  107. package/package.json +96 -3
@@ -0,0 +1,20 @@
1
+ /**
2
+ * Level 10, option B: the tool description is the teaching.
3
+ * The prompt says what to ask. The description says how: what Jev is, the three question types, when a typed answer beats reasoning, and when it does not.
4
+ */
5
+ export const ASK_JEV_DESCRIPTION = [
6
+ "Ask Jev, a fast decision model, typed questions about one situation: files, a command's output, your own state, or any mix. It answers in about 300 ms for a fraction of a cent, and each answer is a number you can branch on, not prose. Use it whenever a judgment call would otherwise cost you a long think.",
7
+ "",
8
+ "Do not paste content you already have; that costs output tokens. Pass paths and code reads the files into files[\"path\"]. Pass command and code runs it in the repo and puts the result into output {command, exit_code, stdout, stderr}. Use state for what only you can say: a customer report, your plan, a line of context. Plain text or a JSON object as a string; your field names are kept as is. You can combine all three, and you never receive the files or the output, only the answers.",
9
+ "",
10
+ "One call judges one situation: up to 20 files and about 60k tokens in total. Over that the call is refused with a message naming the parts and a split that fits; make two calls with the same questions_json. For many files judged separately use ask_jev_files instead.",
11
+ "",
12
+ "questions_json: a JSON object keyed by question id. Three types:",
13
+ ' noul {"type":"noul","instructions":"Is `output` a real failure rather than a flaky one?","criteria":{"true":"...","false":"..."}} -> { noul: 0..1 }',
14
+ ' choice {"type":"choice","instructions":"What kind of failure is `output`?","criteria":{"bug_in_code":"...","wrong_test":"...","environment":"...","other":"..."}} -> { choice, confidence, probabilities }',
15
+ ' score {"type":"score","instructions":"How risky is `diff`?","criteria":["Isolated, tested","Some callers","Security sensitive, no tests"]} -> { score, confidence, legend }',
16
+ "",
17
+ "Write questions against files[\"path\"], output, or your own field names. Good uses: run the tests through command and classify the failure before choosing a fix, put git diff through command and score its risk before committing, pass the customer's words as state with the relevant paths and decide bug or expected, decide whether a request is clear enough to plan.",
18
+ "Ask every question you might need in one call; they share the state. Always give a choice an `other` option. Describe situations, not degrees.",
19
+ "Not for: exact lookups, counting, math, or anything a grep answers. Not a substitute for reading code you need to edit.",
20
+ ].join("\n");
@@ -0,0 +1,7 @@
1
+ import { type JevTool } from "./types.ts";
2
+ export declare const QUESTION_SCHEMA: string;
3
+ export declare const askJevFileBool: JevTool;
4
+ export declare const askJevFileChoice: JevTool;
5
+ export declare const askJevFileScore: JevTool;
6
+ export declare const askJevFiles: JevTool;
7
+ export declare const pickFirstFileTool: JevTool;
@@ -0,0 +1,127 @@
1
+ /**
2
+ * Levels 8 and 9: judgments about files the agent never loads.
3
+ *
4
+ * ask_jev_file_bool(path, question, yes?, no?)
5
+ * ask_jev_file_choice(path, question, options)
6
+ * ask_jev_file_score(path, question, levels)
7
+ * ask_jev_files(paths_or_globs, questions_json, recursive?) one call per file, in parallel
8
+ * pick_first_file(question, candidates) a second pass: which to open first
9
+ */
10
+ import { askFileBool } from "../files/ask-file-bool.js";
11
+ import { askFileChoice } from "../files/ask-file-choice.js";
12
+ import { askFileScore } from "../files/ask-file-score.js";
13
+ import { askFiles } from "../files/ask-files.js";
14
+ import { pickFirstFile } from "../files/pick-first.js";
15
+ import { FileStateError } from "../files/read-state.js";
16
+ import { fail, object, ok, str } from "./types.js";
17
+ const WHEN = "Use this for a judgment about what a file does or contains, without reading it into your context. " +
18
+ "Write the question against `content`, which is the file's text. Use the read tool instead when you need the code itself, to edit or quote it. " +
19
+ "Exact lookups, does this string appear, how many lines, belong to grep, not here.";
20
+ export const QUESTION_SCHEMA = 'questions_json is a JSON object keyed by question id. Three types. ' +
21
+ 'noul: {"type":"noul","instructions":"Does `content` ...?","criteria":{"true":"...","false":"..."}} returns a probability of yes. ' +
22
+ 'choice: {"type":"choice","instructions":"Which ... is `content`?","criteria":{"option_a":"when it applies","option_b":"...","other":"none of the above"}} returns one of your keys plus confidence, up to 255 options. ' +
23
+ 'score: {"type":"score","instructions":"How ... is `content`?","criteria":["lowest situation","...","highest situation"]} returns a position on your levels, two to ten of them. ' +
24
+ "Write every question against `content`, the file's text; `path` is also in the state. Ask every question you might need in one block, it is one call per file either way.";
25
+ const fileFail = (err) => fail(err instanceof FileStateError ? err.message : `error: ${err?.message ?? err}`);
26
+ const PATH = str("File path, relative to the repo");
27
+ export const askJevFileBool = {
28
+ name: "ask_jev_file_bool",
29
+ label: "Ask Jev about a file, yes or no",
30
+ description: `Yes or no about one file. Returns { path, answer, noul } where noul is the probability of yes, 0 to 1. ${WHEN}`,
31
+ parameters: object({
32
+ path: PATH,
33
+ question: str("A yes or no question about `content`, for example: Does `content` validate authentication tokens?"),
34
+ yes: str("What counts as yes"),
35
+ no: str("What counts as no"),
36
+ }, ["path", "question"]),
37
+ async execute(p, ctx) {
38
+ try {
39
+ return ok(await askFileBool(p.path, p.question, ctx.cwd, { yes: p.yes, no: p.no }, (s, q) => ctx.decide("ask_jev_file_bool", s, q, { path: p.path })));
40
+ }
41
+ catch (err) {
42
+ return fileFail(err);
43
+ }
44
+ },
45
+ };
46
+ export const askJevFileChoice = {
47
+ name: "ask_jev_file_choice",
48
+ label: "Ask Jev about a file, pick one",
49
+ description: `Pick one option about one file. Returns { path, choice, confidence, probabilities }. The choice is always one of your options; an "other" option is added if you leave none. ${WHEN}`,
50
+ parameters: object({
51
+ path: PATH,
52
+ question: str("The question, for example: Which layer is `content`?"),
53
+ options: { type: "object", additionalProperties: { type: "string" }, description: "Option name to a one line description of when it applies. Up to 255." },
54
+ }),
55
+ async execute(p, ctx) {
56
+ try {
57
+ return ok(await askFileChoice(p.path, p.question, p.options, ctx.cwd, (s, q) => ctx.decide("ask_jev_file_choice", s, q, { path: p.path })));
58
+ }
59
+ catch (err) {
60
+ return fileFail(err);
61
+ }
62
+ },
63
+ };
64
+ export const askJevFileScore = {
65
+ name: "ask_jev_file_score",
66
+ label: "Ask Jev about a file, on a scale",
67
+ description: `A position on a scale you define, about one file. Returns { path, score, top, nearest, confidence, legend }. Levels are ordered low to high, two to ten of them, each a described situation. ${WHEN}`,
68
+ parameters: object({
69
+ path: PATH,
70
+ question: str("The question, for example: How risky is a refactor of `content`?"),
71
+ levels: { type: "array", items: { type: "string" }, description: "Ordered low to high, each level a situation, for example: Isolated and well tested" },
72
+ }),
73
+ async execute(p, ctx) {
74
+ try {
75
+ return ok(await askFileScore(p.path, p.question, p.levels, ctx.cwd, (s, q) => ctx.decide("ask_jev_file_score", s, q, { path: p.path })));
76
+ }
77
+ catch (err) {
78
+ return fileFail(err);
79
+ }
80
+ },
81
+ };
82
+ export const askJevFiles = {
83
+ name: "ask_jev_files",
84
+ label: "Ask Jev about many files",
85
+ description: "Ask the same typed questions of many files at once without reading any of them. Code expands globs and directories, " +
86
+ "drops node_modules, .git, binaries, and files over the budget, caps the list at 255, then makes one Jev call per file in parallel. " +
87
+ "Returns { results: [{ path, answers }], skipped: [{ path, reason }], calls }. " + QUESTION_SCHEMA +
88
+ " Use read when you need a file's code; use grep for exact strings.",
89
+ parameters: object({
90
+ paths_or_globs: { type: "array", items: { type: "string" }, description: 'Files, directories, or globs, relative to the repo, for example ["src/**/*.ts"] or ["src/http"]' },
91
+ questions_json: str("The question block as a JSON string"),
92
+ recursive: { type: "boolean", description: "For directories: include every file below them. Default false." },
93
+ }, ["paths_or_globs", "questions_json"]),
94
+ async execute(p, ctx) {
95
+ try {
96
+ return ok(await askFiles(p.paths_or_globs, p.questions_json, ctx.cwd, {
97
+ recursive: p.recursive ?? false,
98
+ decide: (s, q) => ctx.decide("ask_jev_files", s, q, { path: s.path }),
99
+ }));
100
+ }
101
+ catch (err) {
102
+ return fail(`error: ${err?.message ?? err}`);
103
+ }
104
+ },
105
+ };
106
+ export const pickFirstFileTool = {
107
+ name: "pick_first_file",
108
+ label: "Pick the file to open first",
109
+ description: "After ask_jev_files, choose which of a list of files to open first for a goal. One Choice keyed by path, so the pick is always a real file. " +
110
+ "Returns { path | null, confidence, probabilities }. Pass a short note per path if you have one, for example the answers you already got.",
111
+ parameters: object({
112
+ question: str("The goal, for example: Which file should I open first to fix the proration bug?"),
113
+ candidates: {
114
+ type: "array",
115
+ items: object({ path: str(), note: str() }, ["path"]),
116
+ description: "Paths, with an optional one line note each",
117
+ },
118
+ }),
119
+ async execute(p, ctx) {
120
+ try {
121
+ return ok(await pickFirstFile(p.question, p.candidates, (s, q) => ctx.decide("pick_first_file", s, q)));
122
+ }
123
+ catch (err) {
124
+ return fail(`error: ${err?.message ?? err}`);
125
+ }
126
+ },
127
+ };
@@ -0,0 +1,10 @@
1
+ /**
2
+ * The Jev tools, one definition per tool for every harness, and the sets each surface exposes.
3
+ */
4
+ export * from "./types.ts";
5
+ export * from "./description.ts";
6
+ export * from "./file-tools.ts";
7
+ export * from "./ask-jev.ts";
8
+ export * from "./compact-tool.ts";
9
+ export * from "./run-command.ts";
10
+ export * from "./sets.ts";
@@ -0,0 +1,10 @@
1
+ /**
2
+ * The Jev tools, one definition per tool for every harness, and the sets each surface exposes.
3
+ */
4
+ export * from "./types.js";
5
+ export * from "./description.js";
6
+ export * from "./file-tools.js";
7
+ export * from "./ask-jev.js";
8
+ export * from "./compact-tool.js";
9
+ export * from "./run-command.js";
10
+ export * from "./sets.js";
@@ -0,0 +1,7 @@
1
+ import { type CommandOutput, type RunCommand } from "../files/assemble.ts";
2
+ import type { ToolContext } from "./types.ts";
3
+ export declare const COMMAND_TIMEOUT_MS = 60000;
4
+ export declare const MAX_OUTPUT_CHARS = 200000;
5
+ export declare function runCommand(command: string, cwd: string): Promise<CommandOutput>;
6
+ /** A runner that refuses what the bash gate blocks, reporting the gate's verdict either way. */
7
+ export declare function gatedRunner(ctx: ToolContext, run?: RunCommand): RunCommand;
@@ -0,0 +1,27 @@
1
+ /**
2
+ * Run a command for a state. The output is captured, never streamed to the agent, and the
3
+ * command passes the bash gate first: a state should only ever need reads.
4
+ */
5
+ import { exec } from "node:child_process";
6
+ import { BLOCK_NOTICE, gateBashCommand } from "../guards/bash-gate.js";
7
+ import { AskStateError } from "../files/assemble.js";
8
+ export const COMMAND_TIMEOUT_MS = 60_000;
9
+ export const MAX_OUTPUT_CHARS = 200_000;
10
+ export function runCommand(command, cwd) {
11
+ return new Promise((resolve) => {
12
+ exec(command, { cwd, timeout: COMMAND_TIMEOUT_MS, maxBuffer: MAX_OUTPUT_CHARS * 4, env: { ...process.env, CI: "1" } }, (err, stdout, stderr) => {
13
+ const code = err && typeof err.code === "number" ? err.code : err ? null : 0;
14
+ resolve({ command, exit_code: code, stdout: String(stdout).slice(0, MAX_OUTPUT_CHARS), stderr: String(stderr).slice(0, MAX_OUTPUT_CHARS) });
15
+ });
16
+ });
17
+ }
18
+ /** A runner that refuses what the bash gate blocks, reporting the gate's verdict either way. */
19
+ export function gatedRunner(ctx, run = runCommand) {
20
+ return async (command, cwd) => {
21
+ const gate = await gateBashCommand(command, cwd, (s, q) => ctx.decide("ask_jev command gate", s, q));
22
+ ctx.report("hook", { hook: "ask_jev command", tool: "bash", command, block: gate.block, reason: gate.reason });
23
+ if (gate.block)
24
+ throw new AskStateError(`ask_jev: the command was refused by the bash gate: ${gate.reason}. ${BLOCK_NOTICE} ask_jev commands should only read.`);
25
+ return run(command, cwd);
26
+ };
27
+ }
@@ -0,0 +1,9 @@
1
+ import type { JevTool } from "./types.ts";
2
+ export declare const ALL_TOOLS: JevTool[];
3
+ export declare const LEVEL_TOOLS: Record<number, string[]>;
4
+ export declare const toolByName: (name: string) => JevTool | undefined;
5
+ /** By level, by names, or all of them. Unknown names and levels are errors, not silent drops. */
6
+ export declare function selectTools(opts?: {
7
+ level?: number;
8
+ names?: string[];
9
+ }): JevTool[];
@@ -0,0 +1,32 @@
1
+ /**
2
+ * Which tools a surface exposes. The package speaks tool names; level numbers are the lab's alias.
3
+ */
4
+ import { askJev } from "./ask-jev.js";
5
+ import { shouldICompact } from "./compact-tool.js";
6
+ import { askJevFileBool, askJevFileChoice, askJevFileScore, askJevFiles, pickFirstFileTool } from "./file-tools.js";
7
+ export const ALL_TOOLS = [shouldICompact, askJevFileBool, askJevFileChoice, askJevFileScore, askJevFiles, pickFirstFileTool, askJev];
8
+ export const LEVEL_TOOLS = {
9
+ 7: ["should_i_compact"],
10
+ 8: ["ask_jev_file_bool", "ask_jev_file_choice", "ask_jev_file_score"],
11
+ 9: ["ask_jev_files", "pick_first_file"],
12
+ 10: ["ask_jev"],
13
+ };
14
+ export const toolByName = (name) => ALL_TOOLS.find((t) => t.name === name);
15
+ /** By level, by names, or all of them. Unknown names and levels are errors, not silent drops. */
16
+ export function selectTools(opts = {}) {
17
+ if (opts.level !== undefined && opts.names?.length)
18
+ throw new Error("pass a level or tool names, not both");
19
+ if (opts.level !== undefined) {
20
+ const names = LEVEL_TOOLS[opts.level];
21
+ if (!names)
22
+ throw new Error(`no Jev tools for level ${opts.level}; tools exist for levels ${Object.keys(LEVEL_TOOLS).join(", ")}`);
23
+ return names.map((n) => toolByName(n));
24
+ }
25
+ if (opts.names?.length) {
26
+ const unknown = opts.names.filter((n) => !toolByName(n));
27
+ if (unknown.length)
28
+ throw new Error(`unknown tool ${unknown.join(", ")}; known: ${ALL_TOOLS.map((t) => t.name).join(", ")}`);
29
+ return opts.names.map((n) => toolByName(n));
30
+ }
31
+ return ALL_TOOLS;
32
+ }
@@ -0,0 +1,51 @@
1
+ /**
2
+ * A Jev tool, defined once for every harness: pi registers it, the MCP server lists it, the CLI
3
+ * runs it. The name, description, parameters, and payload are the same wherever it appears.
4
+ */
5
+ import type { Decider } from "../events/index.ts";
6
+ import type { CompactAction } from "../compact/should-compact.ts";
7
+ import type { Evaluation, TurnInput } from "../compact/evaluate.ts";
8
+ /** The subset of JSON Schema the tools use. */
9
+ export interface JsonSchema {
10
+ type?: "object" | "string" | "boolean" | "array" | "number" | "integer";
11
+ description?: string;
12
+ properties?: Record<string, JsonSchema>;
13
+ required?: string[];
14
+ items?: JsonSchema;
15
+ additionalProperties?: boolean | JsonSchema;
16
+ }
17
+ export interface CompactionSource {
18
+ /** The session as the harness sees it, or null when it has no history to offer. */
19
+ input(): TurnInput | null | Promise<TurnInput | null>;
20
+ /** How the agent can act on a tier under this harness. */
21
+ action: CompactAction;
22
+ /** Told about every evaluation, so a harness can keep injecting the latest tier. */
23
+ onEvaluation?(evaluation: Evaluation): void;
24
+ }
25
+ export interface ToolContext {
26
+ /** The directory the agent works in. Paths resolve here and may not leave it. */
27
+ cwd: string;
28
+ harness: string;
29
+ decide: Decider;
30
+ report(kind: string, payload: Record<string, unknown>): void;
31
+ /** Level 7 only. */
32
+ compaction?: CompactionSource;
33
+ }
34
+ export interface ToolResult {
35
+ /** What the agent reads. */
36
+ text: string;
37
+ /** The structured result, when the call succeeded. */
38
+ payload?: unknown;
39
+ isError?: boolean;
40
+ }
41
+ export interface JevTool {
42
+ name: string;
43
+ label: string;
44
+ description: string;
45
+ parameters: JsonSchema;
46
+ execute(params: Record<string, unknown>, ctx: ToolContext): Promise<ToolResult>;
47
+ }
48
+ export declare const ok: (payload: unknown) => ToolResult;
49
+ export declare const fail: (text: string) => ToolResult;
50
+ export declare const object: (properties: Record<string, JsonSchema>, required?: string[]) => JsonSchema;
51
+ export declare const str: (description?: string) => JsonSchema;
@@ -0,0 +1,4 @@
1
+ export const ok = (payload) => ({ text: JSON.stringify(payload, null, 2), payload });
2
+ export const fail = (text) => ({ text, isError: true });
3
+ export const object = (properties, required = Object.keys(properties)) => ({ type: "object", properties, required });
4
+ export const str = (description) => (description ? { type: "string", description } : { type: "string" });
package/package.json CHANGED
@@ -1,6 +1,99 @@
1
1
  {
2
2
  "name": "@bobobowis/jev-kit",
3
- "version": "0.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
3
+ "version": "0.2.0",
4
+ "description": "Jev, TypeSafe AI's System One decision model, as a typed client, guards, file reads, agent tools, hooks, an MCP server, and a CLI. Zero runtime dependencies.",
5
+ "type": "module",
6
+ "license": "MIT",
7
+ "author": "bobobowis",
8
+ "repository": {
9
+ "type": "git",
10
+ "url": "git+https://github.com/bobobowis/ten-levels-of-jev.git",
11
+ "directory": "packages/jev-kit"
12
+ },
13
+ "homepage": "https://github.com/bobobowis/ten-levels-of-jev/tree/main/packages/jev-kit#readme",
14
+ "bugs": "https://github.com/bobobowis/ten-levels-of-jev/issues",
15
+ "keywords": [
16
+ "jev",
17
+ "typesafe",
18
+ "llm",
19
+ "classifier",
20
+ "decision",
21
+ "guardrails",
22
+ "claude-code",
23
+ "codex",
24
+ "mcp",
25
+ "hooks",
26
+ "agents"
27
+ ],
28
+ "publishConfig": {
29
+ "access": "public"
30
+ },
31
+ "engines": {
32
+ "node": ">=22.18"
33
+ },
34
+ "exports": {
35
+ ".": {
36
+ "types": "./dist/index.d.ts",
37
+ "default": "./dist/index.js"
38
+ },
39
+ "./policy": {
40
+ "types": "./dist/policy/index.d.ts",
41
+ "default": "./dist/policy/index.js"
42
+ },
43
+ "./events": {
44
+ "types": "./dist/events/index.d.ts",
45
+ "default": "./dist/events/index.js"
46
+ },
47
+ "./files": {
48
+ "types": "./dist/files/index.d.ts",
49
+ "default": "./dist/files/index.js"
50
+ },
51
+ "./ledger": {
52
+ "types": "./dist/ledger.d.ts",
53
+ "default": "./dist/ledger.js"
54
+ },
55
+ "./guards": {
56
+ "types": "./dist/guards/index.d.ts",
57
+ "default": "./dist/guards/index.js"
58
+ },
59
+ "./compact": {
60
+ "types": "./dist/compact/index.d.ts",
61
+ "default": "./dist/compact/index.js"
62
+ },
63
+ "./tools": {
64
+ "types": "./dist/tools/index.d.ts",
65
+ "default": "./dist/tools/index.js"
66
+ },
67
+ "./hooks": {
68
+ "types": "./dist/hooks/index.d.ts",
69
+ "default": "./dist/hooks/index.js"
70
+ },
71
+ "./setup": {
72
+ "types": "./dist/setup/index.d.ts",
73
+ "default": "./dist/setup/index.js"
74
+ },
75
+ "./capabilities": {
76
+ "types": "./dist/capabilities.d.ts",
77
+ "default": "./dist/capabilities.js"
78
+ },
79
+ "./package.json": "./package.json"
80
+ },
81
+ "bin": {
82
+ "jev": "./dist/cli/index.js"
83
+ },
84
+ "files": [
85
+ "dist",
86
+ "README.md",
87
+ "LICENSE"
88
+ ],
89
+ "devDependencies": {
90
+ "@types/node": "^24.0.0",
91
+ "typescript": "~5.9.3"
92
+ },
93
+ "scripts": {
94
+ "build": "tsc -b tsconfig.build.json",
95
+ "pretest": "tsc -b tsconfig.build.json",
96
+ "test": "node --test \"tests/**/*.test.ts\"",
97
+ "typecheck": "tsc -p tsconfig.json"
98
+ }
6
99
  }