auto-mode 0.8.0 → 0.9.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/README.md +1 -2
- package/dist/cli.js +2 -45
- package/dist/index.js +1 -1
- package/dist/{render-verdict-DePMDXKz.js → render-verdict-CK9sRJpa.js} +4 -125
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -38,7 +38,7 @@ Create the classifier configuration:
|
|
|
38
38
|
|
|
39
39
|
Save it as `~/.config/auto-mode/config.json` and export your TypeSafe API key, or set the entry's
|
|
40
40
|
`apiKeyCommand` to a command that prints it. [Configuration](./docs/guides/configuration.md) covers
|
|
41
|
-
the registries
|
|
41
|
+
the registries and credentials.
|
|
42
42
|
|
|
43
43
|
## Standing permissions
|
|
44
44
|
|
|
@@ -77,7 +77,6 @@ fit.
|
|
|
77
77
|
| `auto-mode run --local-only` | Skip the model tier |
|
|
78
78
|
| `auto-mode run --jev-only` | Require Jev with a 5-second API timeout |
|
|
79
79
|
| `auto-mode print-prompt` | Print the selected provider's base policy |
|
|
80
|
-
| `auto-mode config migrate` | Rewrite an older config file in place |
|
|
81
80
|
|
|
82
81
|
The mod evaluates only ask decisions and preserves existing allow and deny decisions. It runs the
|
|
83
82
|
CLI as a bounded child process with `--jev-only`. The `spark`, `claude`, `glm`, and `messages`
|
package/dist/cli.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import {
|
|
3
|
-
import { appendFile,
|
|
2
|
+
import { g as string, h as strictObject, l as DEFAULT_DENIAL_BUDGET, m as number, n as parseActionRequest, r as classifyAction, s as loadPolicy, t as renderVerdict, u as loadConfig } from "./render-verdict-CK9sRJpa.js";
|
|
3
|
+
import { appendFile, mkdir, readFile, rename, writeFile } from "node:fs/promises";
|
|
4
4
|
import { homedir } from "node:os";
|
|
5
5
|
import { dirname, join } from "node:path";
|
|
6
6
|
import { createHash, randomUUID } from "node:crypto";
|
|
@@ -154,36 +154,6 @@ function buildJevOnlyConfig(config) {
|
|
|
154
154
|
};
|
|
155
155
|
}
|
|
156
156
|
//#endregion
|
|
157
|
-
//#region src/config/write-migrated-config.ts
|
|
158
|
-
async function writeMigratedConfig(path) {
|
|
159
|
-
let raw;
|
|
160
|
-
try {
|
|
161
|
-
raw = await readFile(path, "utf8");
|
|
162
|
-
} catch (error) {
|
|
163
|
-
if (error instanceof Error && "code" in error && error.code === "ENOENT") return `${path} does not exist; nothing to migrate`;
|
|
164
|
-
throw new Error(`${path} is unreadable`, { cause: error });
|
|
165
|
-
}
|
|
166
|
-
let json;
|
|
167
|
-
try {
|
|
168
|
-
json = JSON.parse(raw);
|
|
169
|
-
} catch {
|
|
170
|
-
throw new Error(`${path} is not valid JSON`);
|
|
171
|
-
}
|
|
172
|
-
const normalized = normalizeConfigFile(json, path);
|
|
173
|
-
if (!normalized.isLegacy) return `${path} already uses the current shape`;
|
|
174
|
-
const backup = `${path}.bak`;
|
|
175
|
-
const staged = `${path}.migrating`;
|
|
176
|
-
try {
|
|
177
|
-
await copyFile(path, backup, constants.COPYFILE_EXCL);
|
|
178
|
-
} catch (error) {
|
|
179
|
-
if (error instanceof Error && "code" in error && error.code === "EEXIST") throw new Error(`${backup} already exists; move it aside and run the migration again`, { cause: error });
|
|
180
|
-
throw error;
|
|
181
|
-
}
|
|
182
|
-
await writeFile(staged, `${JSON.stringify(normalized.file, null, 2)}\n`, { mode: 384 });
|
|
183
|
-
await rename(staged, path);
|
|
184
|
-
return `rewrote ${path} in the current shape; the old file is at ${backup}`;
|
|
185
|
-
}
|
|
186
|
-
//#endregion
|
|
187
157
|
//#region src/diagnostics/write-action-diagnostic.ts
|
|
188
158
|
async function writeActionDiagnostic(payload, entry) {
|
|
189
159
|
const path = process.env["AUTO_MODE_DIAGNOSTICS_PATH"] ?? join(resolveStateDir(), "actions.jsonl");
|
|
@@ -221,7 +191,6 @@ const USAGE = `auto-mode — a permission classifier for the auto-mode Claude Co
|
|
|
221
191
|
Usage:
|
|
222
192
|
auto-mode run Read an action request on stdin, write a verdict on stdout
|
|
223
193
|
auto-mode print-prompt Print the system prompt the classifier receives
|
|
224
|
-
auto-mode config migrate Rewrite the config file from the old keys into the current shape
|
|
225
194
|
|
|
226
195
|
Options:
|
|
227
196
|
--classifier <path> Use this framework file instead of the shipped one
|
|
@@ -381,21 +350,9 @@ async function main(argv) {
|
|
|
381
350
|
process.stdout.write(`${prompt}\n`);
|
|
382
351
|
return 0;
|
|
383
352
|
}
|
|
384
|
-
if (command === "config" && args.positionals[1] === "migrate") return runConfigMigration();
|
|
385
353
|
process.stderr.write(`auto-mode: unknown command '${command}'\n\n${USAGE}`);
|
|
386
354
|
return 2;
|
|
387
355
|
}
|
|
388
|
-
async function runConfigMigration() {
|
|
389
|
-
const path = resolveConfigPath();
|
|
390
|
-
try {
|
|
391
|
-
const result = await writeMigratedConfig(path);
|
|
392
|
-
process.stdout.write(`${result}\n`);
|
|
393
|
-
return 0;
|
|
394
|
-
} catch (error) {
|
|
395
|
-
process.stderr.write(`auto-mode: ${error instanceof Error ? error.message : "config migration failed"}\n`);
|
|
396
|
-
return 1;
|
|
397
|
-
}
|
|
398
|
-
}
|
|
399
356
|
process.exitCode = await main(process.argv.slice(2));
|
|
400
357
|
//#endregion
|
|
401
358
|
export {};
|
package/dist/index.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { a as classifyWithModel, c as DEFAULT_CONFIG, d as resolveApiKey, f as resolveConfigPath, i as classifyLocally,
|
|
1
|
+
import { a as classifyWithModel, c as DEFAULT_CONFIG, d as resolveApiKey, f as resolveConfigPath, i as classifyLocally, n as parseActionRequest, o as parseModelVerdict, p as PRESETS, r as classifyAction, s as loadPolicy, t as renderVerdict, u as loadConfig } from "./render-verdict-CK9sRJpa.js";
|
|
2
2
|
export { DEFAULT_CONFIG, PRESETS, classifyAction, classifyLocally, classifyWithModel, loadConfig, loadPolicy, parseActionRequest, parseModelVerdict, renderVerdict, resolveApiKey, resolveConfigPath };
|
|
@@ -5615,126 +5615,6 @@ function findPreset(id) {
|
|
|
5615
5615
|
return Object.hasOwn(PRESETS, id) ? PRESETS[id] : void 0;
|
|
5616
5616
|
}
|
|
5617
5617
|
//#endregion
|
|
5618
|
-
//#region src/config/normalize-config-file.ts
|
|
5619
|
-
function normalizeConfigFile(json, path) {
|
|
5620
|
-
if (!isRecord(json)) return {
|
|
5621
|
-
file: json,
|
|
5622
|
-
isLegacy: false,
|
|
5623
|
-
warnings: []
|
|
5624
|
-
};
|
|
5625
|
-
const legacyKeys = Object.keys(json).filter((key) => LEGACY_KEYS.has(key));
|
|
5626
|
-
if (legacyKeys.length === 0) return {
|
|
5627
|
-
file: json,
|
|
5628
|
-
isLegacy: false,
|
|
5629
|
-
warnings: []
|
|
5630
|
-
};
|
|
5631
|
-
const currentKeys = Object.keys(json).filter((key) => !LEGACY_KEYS.has(key));
|
|
5632
|
-
if (currentKeys.length > 0) throw new Error(`${path} mixes the old keys (${legacyKeys.join(", ")}) with the new ones (${currentKeys.join(", ")}); run \`auto-mode config migrate\` on a copy without the new keys`);
|
|
5633
|
-
const parsed = legacyConfigSchema.safeParse(json);
|
|
5634
|
-
if (!parsed.success) throw new Error(`${path} is not a valid config: ${prettifyError(parsed.error)}`);
|
|
5635
|
-
const legacy = parsed.data;
|
|
5636
|
-
const warnings = [`${path} uses the old config keys (${legacyKeys.join(", ")}); run \`auto-mode config migrate\` to rewrite it`, ...legacy.transcriptEntries === void 0 ? [] : [`${path} sets transcriptEntries, which has no effect; migration drops it`]];
|
|
5637
|
-
return {
|
|
5638
|
-
file: buildFileFromLegacy(legacy, path),
|
|
5639
|
-
isLegacy: true,
|
|
5640
|
-
warnings
|
|
5641
|
-
};
|
|
5642
|
-
}
|
|
5643
|
-
function isRecord(value) {
|
|
5644
|
-
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
5645
|
-
}
|
|
5646
|
-
const LEGACY_KEYS = /* @__PURE__ */ new Set([
|
|
5647
|
-
"preset",
|
|
5648
|
-
"provider",
|
|
5649
|
-
"classifierPath",
|
|
5650
|
-
"rulesPath",
|
|
5651
|
-
"transcriptEntries",
|
|
5652
|
-
"onFailure",
|
|
5653
|
-
"claudeSettingsPath",
|
|
5654
|
-
"minConfidence"
|
|
5655
|
-
]);
|
|
5656
|
-
const text$1 = string().min(1);
|
|
5657
|
-
const positive$1 = number().positive();
|
|
5658
|
-
const legacyConfigSchema = strictObject({
|
|
5659
|
-
preset: text$1.optional(),
|
|
5660
|
-
provider: strictObject({
|
|
5661
|
-
protocol: _enum(["messages", "system-one"]).optional(),
|
|
5662
|
-
baseURL: text$1.optional(),
|
|
5663
|
-
model: text$1.optional(),
|
|
5664
|
-
apiKeyEnv: text$1.optional(),
|
|
5665
|
-
apiKeyCommand: text$1.optional(),
|
|
5666
|
-
reasoning: boolean().optional(),
|
|
5667
|
-
maxTokens: positive$1.optional(),
|
|
5668
|
-
timeoutMs: positive$1.optional()
|
|
5669
|
-
}).optional(),
|
|
5670
|
-
classifierPath: text$1.optional(),
|
|
5671
|
-
rulesPath: text$1.optional(),
|
|
5672
|
-
transcriptEntries: number().nonnegative().optional(),
|
|
5673
|
-
onFailure: _enum(["defer", "deny"]).optional(),
|
|
5674
|
-
claudeSettingsPath: text$1.nullable().optional(),
|
|
5675
|
-
minConfidence: number().min(.5).max(1).optional()
|
|
5676
|
-
});
|
|
5677
|
-
function buildFileFromLegacy(legacy, path) {
|
|
5678
|
-
const hasClassifier = legacy.preset !== void 0 || legacy.provider !== void 0;
|
|
5679
|
-
const decision = {
|
|
5680
|
-
...hasClassifier ? { classifier: getLegacyClassifierID(legacy) } : {},
|
|
5681
|
-
...legacy.minConfidence === void 0 ? {} : { minConfidence: legacy.minConfidence },
|
|
5682
|
-
...legacy.onFailure === void 0 ? {} : { onFailure: legacy.onFailure }
|
|
5683
|
-
};
|
|
5684
|
-
const policy = {
|
|
5685
|
-
...legacy.rulesPath === void 0 ? {} : { rulesPath: legacy.rulesPath },
|
|
5686
|
-
...legacy.classifierPath === void 0 ? {} : { frameworkPath: legacy.classifierPath },
|
|
5687
|
-
...legacy.claudeSettingsPath === void 0 ? {} : { claudeSettingsPath: legacy.claudeSettingsPath }
|
|
5688
|
-
};
|
|
5689
|
-
return {
|
|
5690
|
-
...hasClassifier ? { classifiers: { [getLegacyClassifierID(legacy)]: buildClassifierEntry(getLegacyClassifierID(legacy), buildLegacyProvider(legacy, path)) } } : {},
|
|
5691
|
-
...Object.keys(decision).length === 0 ? {} : { decision },
|
|
5692
|
-
...Object.keys(policy).length === 0 ? {} : { policy }
|
|
5693
|
-
};
|
|
5694
|
-
}
|
|
5695
|
-
function getLegacyClassifierID(legacy) {
|
|
5696
|
-
if (legacy.preset !== void 0) return legacy.preset;
|
|
5697
|
-
return legacy.provider !== void 0 && legacy.provider.protocol !== "system-one" ? "spark" : "jev";
|
|
5698
|
-
}
|
|
5699
|
-
function buildLegacyProvider(legacy, path) {
|
|
5700
|
-
const preset = findPreset(getLegacyClassifierID(legacy));
|
|
5701
|
-
if (preset === void 0) throw new Error(`${path} names an unknown preset '${legacy.preset}'; known presets are ${Object.keys(PRESETS).join(", ")}`);
|
|
5702
|
-
const override = legacy.provider ?? {};
|
|
5703
|
-
return {
|
|
5704
|
-
protocol: override.protocol ?? preset.protocol ?? "messages",
|
|
5705
|
-
baseURL: override.baseURL ?? preset.baseURL,
|
|
5706
|
-
model: override.model ?? preset.model,
|
|
5707
|
-
apiKeyEnv: override.apiKeyEnv ?? preset.apiKeyEnv,
|
|
5708
|
-
apiKeyCommand: override.apiKeyCommand ?? preset.apiKeyCommand,
|
|
5709
|
-
reasoning: override.reasoning ?? preset.reasoning,
|
|
5710
|
-
maxTokens: override.maxTokens ?? preset.maxTokens,
|
|
5711
|
-
timeoutMs: override.timeoutMs ?? preset.timeoutMs
|
|
5712
|
-
};
|
|
5713
|
-
}
|
|
5714
|
-
const PROVIDER_FIELDS = [
|
|
5715
|
-
"baseURL",
|
|
5716
|
-
"model",
|
|
5717
|
-
"apiKeyEnv",
|
|
5718
|
-
"apiKeyCommand",
|
|
5719
|
-
"reasoning",
|
|
5720
|
-
"maxTokens",
|
|
5721
|
-
"timeoutMs"
|
|
5722
|
-
];
|
|
5723
|
-
function buildClassifierEntry(id, provider) {
|
|
5724
|
-
const kind = pickEntryKind(id, provider);
|
|
5725
|
-
const base = kind === "messages" ? MESSAGES_DEFAULTS : findPreset(kind) ?? {};
|
|
5726
|
-
const fields = Object.fromEntries(PROVIDER_FIELDS.filter((field) => provider[field] !== void 0 && provider[field] !== base[field]).map((field) => [field, provider[field]]));
|
|
5727
|
-
return {
|
|
5728
|
-
...kind === id ? {} : { kind },
|
|
5729
|
-
...fields
|
|
5730
|
-
};
|
|
5731
|
-
}
|
|
5732
|
-
function pickEntryKind(id, provider) {
|
|
5733
|
-
const preset = findPreset(id);
|
|
5734
|
-
if (preset !== void 0 && (preset.protocol ?? "messages") === provider.protocol) return id;
|
|
5735
|
-
return provider.protocol === "system-one" ? "jev" : "messages";
|
|
5736
|
-
}
|
|
5737
|
-
//#endregion
|
|
5738
5618
|
//#region src/config/read-api-key-from-command.ts
|
|
5739
5619
|
function readApiKeyFromCommand(command, options = {}) {
|
|
5740
5620
|
const remainingMs = options.deadlineAt === void 0 ? 5e3 : options.deadlineAt - Date.now();
|
|
@@ -5826,8 +5706,7 @@ async function loadConfig(path = resolveConfigPath()) {
|
|
|
5826
5706
|
} catch {
|
|
5827
5707
|
throw new Error(`${path} is not valid JSON`);
|
|
5828
5708
|
}
|
|
5829
|
-
|
|
5830
|
-
return buildConfig(normalized.file, path, normalized.warnings);
|
|
5709
|
+
return buildConfig(json, path);
|
|
5831
5710
|
}
|
|
5832
5711
|
const text = string().min(1);
|
|
5833
5712
|
const positive = number().positive();
|
|
@@ -5851,11 +5730,11 @@ const configFileSchema = strictObject({
|
|
|
5851
5730
|
claudeSettingsPath: text.nullable().optional()
|
|
5852
5731
|
}).optional()
|
|
5853
5732
|
});
|
|
5854
|
-
function buildConfig(json, path
|
|
5733
|
+
function buildConfig(json, path) {
|
|
5855
5734
|
const parsed = configFileSchema.safeParse(json);
|
|
5856
5735
|
if (!parsed.success) throw new Error(`${path} is not a valid config: ${prettifyError(parsed.error)}`);
|
|
5857
5736
|
const file = parsed.data;
|
|
5858
|
-
const warnings = [
|
|
5737
|
+
const warnings = [];
|
|
5859
5738
|
const classifiers = buildRegistry(file.classifiers ?? {}, (id, entry) => parseClassifierEntry(id, entry));
|
|
5860
5739
|
const scopeSources = buildRegistry(file.scopeSources ?? {}, (id, entry) => parseScopeSourceEntry(id, entry));
|
|
5861
5740
|
warnings.push(...classifiers.dropped.map((line) => `${path}: classifiers.${line}`), ...scopeSources.dropped.map((line) => `${path}: scopeSources.${line}`));
|
|
@@ -7318,4 +7197,4 @@ function renderVerdict(verdict) {
|
|
|
7318
7197
|
})).exhaustive();
|
|
7319
7198
|
}
|
|
7320
7199
|
//#endregion
|
|
7321
|
-
export {
|
|
7200
|
+
export { classifyWithModel as a, DEFAULT_CONFIG as c, resolveApiKey as d, resolveConfigPath as f, string as g, strictObject as h, classifyLocally as i, DEFAULT_DENIAL_BUDGET as l, number as m, parseActionRequest as n, parseModelVerdict as o, PRESETS as p, classifyAction as r, loadPolicy as s, renderVerdict as t, loadConfig as u };
|