jev-affected 0.1.0 → 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.
- package/CHANGELOG.md +6 -0
- package/EVALUATION.md +6 -6
- package/README.md +5 -9
- package/SECURITY.md +1 -1
- package/dist/cli.js +4 -4
- package/dist/config.d.ts +2 -0
- package/dist/config.js +13 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/planner.js +2 -1
- package/dist/provider.d.ts +1 -0
- package/dist/provider.js +1 -0
- package/package.json +1 -3
- package/skills/jev-affected/SKILL.md +3 -4
- package/.env.example +0 -3
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.2.0
|
|
4
|
+
|
|
5
|
+
- Read API credentials from the process environment only.
|
|
6
|
+
- Reject literal API keys in YAML configuration.
|
|
7
|
+
- Accept `TYPESAFEAI_API_KEY` as a compatibility fallback.
|
|
8
|
+
|
|
3
9
|
## 0.1.0
|
|
4
10
|
|
|
5
11
|
- YAML semantic task conditions, deterministic globs and protected tasks.
|
package/EVALUATION.md
CHANGED
|
@@ -34,10 +34,10 @@ Run on 2026-09-21 with `jev-1.13.0` and `skipBelow: 0.10`:
|
|
|
34
34
|
| False skips | 0 |
|
|
35
35
|
| Invalid cases | 0 |
|
|
36
36
|
| Cases with reduction | 6 |
|
|
37
|
-
| Task reduction |
|
|
38
|
-
| Unnecessary-run rate |
|
|
37
|
+
| Task reduction | 42.86% |
|
|
38
|
+
| Unnecessary-run rate | 50.00% |
|
|
39
39
|
| API calls | 7 |
|
|
40
|
-
| Total latency | 2,
|
|
40
|
+
| Total latency | 2,126 ms |
|
|
41
41
|
| Input tokens | 2,882 |
|
|
42
42
|
| Output tokens | 476 |
|
|
43
43
|
|
|
@@ -47,7 +47,7 @@ Selected tasks by fixture:
|
|
|
47
47
|
| --- | ---: |
|
|
48
48
|
| API field | 3 / 4 |
|
|
49
49
|
| Authentication | 4 / 4 |
|
|
50
|
-
| Comment |
|
|
50
|
+
| Comment | 2 / 4 |
|
|
51
51
|
| Database schema | 3 / 4 |
|
|
52
52
|
| Documentation | 0 / 4 |
|
|
53
53
|
| Logging | 1 / 4 |
|
|
@@ -65,8 +65,8 @@ pnpm eval:live
|
|
|
65
65
|
|
|
66
66
|
`pnpm eval` uses deterministic synthetic answers and verifies evaluation and
|
|
67
67
|
decision plumbing without making a network request. `pnpm eval:live` reads
|
|
68
|
-
`TYPESAFE_API_KEY` from the process environment
|
|
69
|
-
|
|
68
|
+
`TYPESAFE_API_KEY` from the process environment and sends the fixture inputs to
|
|
69
|
+
Jev. Dotenv files are not loaded.
|
|
70
70
|
|
|
71
71
|
## Limits
|
|
72
72
|
|
package/README.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
<p align="center"><strong>Semantic task routing for software development.</strong></p>
|
|
4
4
|
<p align="center">Run tasks based on what changed, not where it changed.</p>
|
|
5
|
-
<p align="center">v0.
|
|
5
|
+
<p align="center">v0.2.0 Public Beta · Node.js 20+ · TypeScript · MIT · Jev-powered</p>
|
|
6
6
|
|
|
7
7
|

|
|
8
8
|
|
|
@@ -30,13 +30,7 @@ npm install -D jev-affected
|
|
|
30
30
|
npx jev-affected init
|
|
31
31
|
```
|
|
32
32
|
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
```dotenv
|
|
36
|
-
TYPESAFE_API_KEY=your_api_key_here
|
|
37
|
-
```
|
|
38
|
-
|
|
39
|
-
`.env` is ignored by this repository's generated `.gitignore`. Never put the key in `jev-affected.yml` or commit it. An existing process environment value takes precedence over `.env`. You can also set it for the current shell:
|
|
33
|
+
Set the API key in the process environment. The CLI does not read dotenv files or accept API keys in `jev-affected.yml`.
|
|
40
34
|
|
|
41
35
|
```powershell
|
|
42
36
|
$env:TYPESAFE_API_KEY = "your_api_key_here"
|
|
@@ -46,6 +40,8 @@ $env:TYPESAFE_API_KEY = "your_api_key_here"
|
|
|
46
40
|
export TYPESAFE_API_KEY="your_api_key_here"
|
|
47
41
|
```
|
|
48
42
|
|
|
43
|
+
For persistent local use, configure the variable in your shell profile or operating-system credential environment. Open a new terminal after changing persistent environment variables. `TYPESAFEAI_API_KEY` is accepted as a compatibility fallback.
|
|
44
|
+
|
|
49
45
|
Configure your own trusted commands, commit your changes on a feature branch, then:
|
|
50
46
|
|
|
51
47
|
```sh
|
|
@@ -176,7 +172,7 @@ See [EVALUATION.md](EVALUATION.md) for the methodology, release gates, latest li
|
|
|
176
172
|
|
|
177
173
|
## Privacy
|
|
178
174
|
|
|
179
|
-
No backend and no telemetry. Data is read locally; semantic inputs go directly to TypeSafe through its SDK. By default, `.env*`, PEM/key files, and names containing `credentials`, `secret` or `token` are withheld. Custom exclusions add to these defaults. Filename exclusions cannot find every secret embedded in arbitrary source files: inspect inputs and use appropriate repository practices. SDK logging is explicitly disabled.
|
|
175
|
+
No backend and no telemetry. Data is read locally; semantic inputs go directly to TypeSafe through its SDK. API keys are read from the process environment only. By default, `.env*`, PEM/key files, and names containing `credentials`, `secret` or `token` are withheld. Custom exclusions add to these defaults. Filename exclusions cannot find every secret embedded in arbitrary source files: inspect inputs and use appropriate repository practices. SDK logging is explicitly disabled.
|
|
180
176
|
|
|
181
177
|
`TYPESAFE_BASE_URL` is honored by the official SDK; inspect this environment setting before use. Review [TypeSafe's data-processing terms](https://typesafe.ai/legal/mca) for your organization.
|
|
182
178
|
|
package/SECURITY.md
CHANGED
|
@@ -10,7 +10,7 @@ Do not post secrets or exploit details in a public issue. Once the public reposi
|
|
|
10
10
|
|
|
11
11
|
## Secret handling
|
|
12
12
|
|
|
13
|
-
Set TYPESAFE_API_KEY through
|
|
13
|
+
Set TYPESAFE_API_KEY through the process environment or CI secret store. The CLI does not load dotenv files and rejects literal API keys in its YAML configuration. The application disables SDK logging and does not emit provider error bodies. Exclusion globs are additive; they cannot detect every embedded secret. Inspect your inputs before enabling remote analysis.
|
|
14
14
|
|
|
15
15
|
## External API calls
|
|
16
16
|
|
package/dist/cli.js
CHANGED
|
@@ -4,13 +4,11 @@ import { resolve } from "node:path";
|
|
|
4
4
|
import { fileURLToPath } from "node:url";
|
|
5
5
|
import { parseArgs } from "node:util";
|
|
6
6
|
import { TypeSafeClient } from "@typesafe-ai/sdk";
|
|
7
|
-
import {
|
|
8
|
-
import { ConfigError, loadConfig, template } from "./config.js";
|
|
7
|
+
import { ConfigError, loadConfig, resolveApiKey, template } from "./config.js";
|
|
9
8
|
import { evaluate } from "./eval.js";
|
|
10
9
|
import { executePlan } from "./executor.js";
|
|
11
10
|
import { collectChanges, matches } from "./git.js";
|
|
12
11
|
import { createPlan } from "./planner.js";
|
|
13
|
-
loadEnvFile({ quiet: true });
|
|
14
12
|
function render(plan) {
|
|
15
13
|
return [
|
|
16
14
|
`jev-affected\n\nBase ${plan.base}\nHead ${plan.head}\nModel ${plan.model ?? "not analyzed"}`,
|
|
@@ -140,11 +138,12 @@ inspect never sends requests. plan never executes task commands.`);
|
|
|
140
138
|
return;
|
|
141
139
|
}
|
|
142
140
|
if (command === "doctor") {
|
|
141
|
+
const apiKey = resolveApiKey();
|
|
143
142
|
const checks = {
|
|
144
143
|
node: Number(process.versions.node.split(".")[0]) >= 20,
|
|
145
144
|
config: true,
|
|
146
145
|
tasks: Object.keys(config.tasks).length.toString(),
|
|
147
|
-
apiKey: !!
|
|
146
|
+
apiKey: !!apiKey,
|
|
148
147
|
};
|
|
149
148
|
try {
|
|
150
149
|
await collectChanges(config, opts);
|
|
@@ -156,6 +155,7 @@ inspect never sends requests. plan never executes task commands.`);
|
|
|
156
155
|
if (checks.apiKey) {
|
|
157
156
|
try {
|
|
158
157
|
await new TypeSafeClient({
|
|
158
|
+
apiKey,
|
|
159
159
|
logLevel: "off",
|
|
160
160
|
timeout: config.analysis.timeoutMs,
|
|
161
161
|
retry: { maxRetries: 0 },
|
package/dist/config.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
2
|
export declare class ConfigError extends Error {
|
|
3
3
|
}
|
|
4
|
+
export declare const API_KEY_VARS: readonly ["TYPESAFE_API_KEY", "TYPESAFEAI_API_KEY"];
|
|
4
5
|
export declare const secretPatterns: string[];
|
|
5
6
|
export declare const configSchema: z.ZodObject<{
|
|
6
7
|
version: z.ZodLiteral<1>;
|
|
@@ -37,5 +38,6 @@ export declare const configSchema: z.ZodObject<{
|
|
|
37
38
|
}, z.core.$strict>;
|
|
38
39
|
export type Config = z.infer<typeof configSchema>;
|
|
39
40
|
export declare function parseConfig(value: unknown): Config;
|
|
41
|
+
export declare function resolveApiKey(env?: NodeJS.ProcessEnv): string | undefined;
|
|
40
42
|
export declare function loadConfig(path?: string): Promise<Config>;
|
|
41
43
|
export declare const template = "version: 1\nmodel: jev-latest\ndefaults:\n skipBelow: 0.10\ntasks:\n unit:\n command: npm test\n when: Could this change alter runtime application behavior?\n typecheck:\n command: npm run typecheck\n always: true\n";
|
package/dist/config.js
CHANGED
|
@@ -3,6 +3,7 @@ import { parse } from "yaml";
|
|
|
3
3
|
import { z } from "zod";
|
|
4
4
|
export class ConfigError extends Error {
|
|
5
5
|
}
|
|
6
|
+
export const API_KEY_VARS = ["TYPESAFE_API_KEY", "TYPESAFEAI_API_KEY"];
|
|
6
7
|
const probability = z.number().min(0).max(1);
|
|
7
8
|
const limits = z
|
|
8
9
|
.object({
|
|
@@ -68,11 +69,23 @@ export const configSchema = z
|
|
|
68
69
|
})
|
|
69
70
|
.strict();
|
|
70
71
|
export function parseConfig(value) {
|
|
72
|
+
if (value && typeof value === "object" && !Array.isArray(value)) {
|
|
73
|
+
const source = value;
|
|
74
|
+
if (Object.hasOwn(source, "apiKey") || Object.hasOwn(source, "api_key"))
|
|
75
|
+
throw new ConfigError("API keys are not supported in jev-affected.yml. Set TYPESAFE_API_KEY in the process environment or CI secret store.");
|
|
76
|
+
}
|
|
71
77
|
const r = configSchema.safeParse(value);
|
|
72
78
|
if (!r.success)
|
|
73
79
|
throw new ConfigError(r.error.issues.map((i) => `${i.path.join(".")}: ${i.message}`).join("\n"));
|
|
74
80
|
return r.data;
|
|
75
81
|
}
|
|
82
|
+
export function resolveApiKey(env = process.env) {
|
|
83
|
+
for (const name of API_KEY_VARS) {
|
|
84
|
+
const value = env[name]?.trim();
|
|
85
|
+
if (value)
|
|
86
|
+
return value;
|
|
87
|
+
}
|
|
88
|
+
}
|
|
76
89
|
export async function loadConfig(path = "jev-affected.yml") {
|
|
77
90
|
try {
|
|
78
91
|
return parseConfig(parse(await readFile(path, "utf8")));
|
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export { type Config, ConfigError, loadConfig, parseConfig } from "./config.js";
|
|
1
|
+
export { API_KEY_VARS, type Config, ConfigError, loadConfig, parseConfig, resolveApiKey, } from "./config.js";
|
|
2
2
|
export { executePlan } from "./executor.js";
|
|
3
3
|
export { type ChangeState, collectChanges } from "./git.js";
|
|
4
4
|
export { createPlan, type Plan, type TaskDecision } from "./planner.js";
|
package/dist/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export { ConfigError, loadConfig, parseConfig } from "./config.js";
|
|
1
|
+
export { API_KEY_VARS, ConfigError, loadConfig, parseConfig, resolveApiKey, } from "./config.js";
|
|
2
2
|
export { executePlan } from "./executor.js";
|
|
3
3
|
export { collectChanges } from "./git.js";
|
|
4
4
|
export { createPlan } from "./planner.js";
|
package/dist/planner.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { createHash } from "node:crypto";
|
|
2
2
|
import { mkdir, readFile, writeFile } from "node:fs/promises";
|
|
3
3
|
import { resolve } from "node:path";
|
|
4
|
-
import { parseConfig, secretPatterns } from "./config.js";
|
|
4
|
+
import { parseConfig, resolveApiKey, secretPatterns, } from "./config.js";
|
|
5
5
|
import { collectChanges, git, matches } from "./git.js";
|
|
6
6
|
import { JevProvider, } from "./provider.js";
|
|
7
7
|
export async function createPlan(input) {
|
|
@@ -87,6 +87,7 @@ export async function createPlan(input) {
|
|
|
87
87
|
questions,
|
|
88
88
|
model: config.model,
|
|
89
89
|
timeoutMs: config.analysis.timeoutMs,
|
|
90
|
+
apiKey: resolveApiKey(),
|
|
90
91
|
});
|
|
91
92
|
}
|
|
92
93
|
if (!result.model || !/^jev-\d+\.\d+\.\d+$/.test(result.model))
|
package/dist/provider.d.ts
CHANGED
package/dist/provider.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "jev-affected",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"description": "Semantic task routing for software development, powered by Jev.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -46,7 +46,6 @@
|
|
|
46
46
|
"SECURITY.md",
|
|
47
47
|
"CODE_OF_CONDUCT.md",
|
|
48
48
|
"EVALUATION.md",
|
|
49
|
-
".env.example",
|
|
50
49
|
"evals",
|
|
51
50
|
"skills"
|
|
52
51
|
],
|
|
@@ -65,7 +64,6 @@
|
|
|
65
64
|
},
|
|
66
65
|
"dependencies": {
|
|
67
66
|
"@typesafe-ai/sdk": "^0.6.0",
|
|
68
|
-
"dotenv": "^17.2.2",
|
|
69
67
|
"picomatch": "^4.0.7",
|
|
70
68
|
"yaml": "^2.9.1",
|
|
71
69
|
"zod": "^4.6.5"
|
|
@@ -31,10 +31,9 @@ compute the merge base.
|
|
|
31
31
|
|
|
32
32
|
## Credentials and data
|
|
33
33
|
|
|
34
|
-
Set `TYPESAFE_API_KEY` in the process environment or
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
`.env`.
|
|
34
|
+
Set `TYPESAFE_API_KEY` in the process environment or CI secret store. Never
|
|
35
|
+
print the value or store the key in `jev-affected.yml`. The CLI does not load
|
|
36
|
+
dotenv files. `TYPESAFEAI_API_KEY` is accepted as a compatibility fallback.
|
|
38
37
|
|
|
39
38
|
`inspect` stays local. `plan`, `why`, and `run` can send the sanitized committed
|
|
40
39
|
diff and configured semantic questions to the provider. Review `inspect` output
|
package/.env.example
DELETED