auto-mode 3.1.4 → 3.1.5
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/cli.js +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/{parse-action-request-DlsgKqiF.js → parse-action-request-CHuF6LYV.js} +149 -68
- package/mods/auto-mode/contract/types.ts +1 -1
- package/mods/auto-mode/hooks/build-prompt-context.ts +5 -2
- package/package.json +2 -1
package/dist/cli.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { C as pickJudgeLane, E as updateJSONFile, S as CLI_LIMITS, T as resolveXDGDir, _ as readCheckout, a as resolveSessionScopePath, b as loadConfig, c as splitGitCommand, d as loadCheckoutFacts, f as writeActionDiagnostic, g as isUnresolvedWord, h as resolveShellPath, i as classifyAction, l as loadPolicy, m as collectShellCommands, n as readRuntime, o as loadSessionScope, p as toRepositorySlug, s as EMPTY_SESSION_SCOPE, t as parseActionRequest, u as resolveShippedPolicyDir, v as readGitEntry, w as M, x as runCapped, y as DEFAULT_SCOPE_SOURCES } from "./parse-action-request-
|
|
2
|
+
import { C as pickJudgeLane, E as updateJSONFile, S as CLI_LIMITS, T as resolveXDGDir, _ as readCheckout, a as resolveSessionScopePath, b as loadConfig, c as splitGitCommand, d as loadCheckoutFacts, f as writeActionDiagnostic, g as isUnresolvedWord, h as resolveShellPath, i as classifyAction, l as loadPolicy, m as collectShellCommands, n as readRuntime, o as loadSessionScope, p as toRepositorySlug, s as EMPTY_SESSION_SCOPE, t as parseActionRequest, u as resolveShippedPolicyDir, v as readGitEntry, w as M, x as runCapped, y as DEFAULT_SCOPE_SOURCES } from "./parse-action-request-CHuF6LYV.js";
|
|
3
3
|
import { a as literal, d as string, i as discriminatedUnion, l as record, p as unknown, r as boolean, s as number, u as strictObject } from "./schemas-B80Yxv6m.js";
|
|
4
4
|
import { createHash, randomUUID } from "node:crypto";
|
|
5
5
|
import { chmod, mkdir, open, readFile, realpath, stat } from "node:fs/promises";
|
package/dist/index.d.ts
CHANGED
|
@@ -147,10 +147,10 @@ type MessageOrigin = (typeof MESSAGE_ORIGINS)[number];
|
|
|
147
147
|
interface UserTask {
|
|
148
148
|
readonly text: string;
|
|
149
149
|
readonly origin: MessageOrigin;
|
|
150
|
+
readonly position?: 'opening' | undefined;
|
|
150
151
|
}
|
|
151
152
|
interface DirectUserMessage extends UserTask {
|
|
152
153
|
readonly freshness?: 'stale' | undefined;
|
|
153
|
-
readonly position?: 'opening' | undefined;
|
|
154
154
|
}
|
|
155
155
|
interface DelegatedTask {
|
|
156
156
|
readonly text: string;
|
package/dist/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { b as loadConfig$1, i as classifyAction$1, n as readRuntime, r as readHostEnvironment, t as parseActionRequest } from "./parse-action-request-
|
|
1
|
+
import { b as loadConfig$1, i as classifyAction$1, n as readRuntime, r as readHostEnvironment, t as parseActionRequest } from "./parse-action-request-CHuF6LYV.js";
|
|
2
2
|
//#region src/index.ts
|
|
3
3
|
function classifyAction(request, config, options = {}) {
|
|
4
4
|
return classifyAction$1(request, config, {
|
|
@@ -251,6 +251,25 @@ async function tryUpdateDenialBudget(stderr, path, plan) {
|
|
|
251
251
|
}
|
|
252
252
|
}
|
|
253
253
|
//#endregion
|
|
254
|
+
//#region src/scope/find-reply-channel.ts
|
|
255
|
+
function findReplyChannel(tool, input, channels) {
|
|
256
|
+
return channels.find((channel) => channel.tool === tool && input[channel.field] === channel.recipient) ?? null;
|
|
257
|
+
}
|
|
258
|
+
//#endregion
|
|
259
|
+
//#region src/bypass/classify-reply-call.ts
|
|
260
|
+
async function classifyReplyCall(call, scope, hasConfiguredDenies) {
|
|
261
|
+
const channel = scope === null ? null : findReplyChannel(call.toolName, call.toolInput, scope.replyChannels);
|
|
262
|
+
if (channel === null) return { kind: "none" };
|
|
263
|
+
if ((await import("./classify-reply-message-CdHLlNXA.js")).classifyReplyMessage(call.toolInput).kind !== "bypass") return { kind: "none" };
|
|
264
|
+
return hasConfiguredDenies ? {
|
|
265
|
+
kind: "exempt",
|
|
266
|
+
rules: ["Outbound Communication"]
|
|
267
|
+
} : {
|
|
268
|
+
kind: "bypass",
|
|
269
|
+
channel
|
|
270
|
+
};
|
|
271
|
+
}
|
|
272
|
+
//#endregion
|
|
254
273
|
//#region src/state/resolve-xdg-dir.ts
|
|
255
274
|
const BASE_DIRS = {
|
|
256
275
|
config: {
|
|
@@ -1098,11 +1117,6 @@ const SCRATCH_PATHS = [
|
|
|
1098
1117
|
"/dev/stderr"
|
|
1099
1118
|
];
|
|
1100
1119
|
//#endregion
|
|
1101
|
-
//#region src/scope/find-reply-channel.ts
|
|
1102
|
-
function findReplyChannel(tool, input, channels) {
|
|
1103
|
-
return channels.find((channel) => channel.tool === tool && input[channel.field] === channel.recipient) ?? null;
|
|
1104
|
-
}
|
|
1105
|
-
//#endregion
|
|
1106
1120
|
//#region src/shell/is-unresolved-word.ts
|
|
1107
1121
|
function isUnresolvedWord(word) {
|
|
1108
1122
|
return /[$`]/u.test(word);
|
|
@@ -3091,7 +3105,7 @@ async function writeActionDiagnostic(payload, entry, host, warnings) {
|
|
|
3091
3105
|
const agentKey = agentID === null ? payload.sessionID : `${payload.sessionID}\0${agentID}`;
|
|
3092
3106
|
const isReviewed = entry.judge !== void 0 || entry.grant !== void 0;
|
|
3093
3107
|
const record = {
|
|
3094
|
-
schemaVersion:
|
|
3108
|
+
schemaVersion: 9,
|
|
3095
3109
|
time: (/* @__PURE__ */ new Date()).toISOString(),
|
|
3096
3110
|
invocationID: entry.invocationID,
|
|
3097
3111
|
sessionHash: toHash(payload.sessionID),
|
|
@@ -3105,7 +3119,8 @@ async function writeActionDiagnostic(payload, entry, host, warnings) {
|
|
|
3105
3119
|
diagnostics: entry.diagnostics ?? null,
|
|
3106
3120
|
judge: entry.judge === void 0 ? null : buildLoggedReview(entry.judge),
|
|
3107
3121
|
grant: entry.grant === void 0 ? null : buildLoggedReview(entry.grant),
|
|
3108
|
-
action: isReviewed ? buildLoggedAction(payload) : null
|
|
3122
|
+
action: isReviewed ? buildLoggedAction(payload) : null,
|
|
3123
|
+
taskEvidence: buildTaskEvidence(entry.taskContext ?? payload.decisionContext)
|
|
3109
3124
|
};
|
|
3110
3125
|
try {
|
|
3111
3126
|
await mkdir(dirname(path), {
|
|
@@ -3159,6 +3174,15 @@ function hasSecret(value) {
|
|
|
3159
3174
|
if (typeof value === "object" && value !== null) return Object.values(value).some((item) => hasSecret(item));
|
|
3160
3175
|
return false;
|
|
3161
3176
|
}
|
|
3177
|
+
function buildTaskEvidence(context) {
|
|
3178
|
+
if (context === void 0) return null;
|
|
3179
|
+
const message = context.lastDirectUserMessage;
|
|
3180
|
+
return {
|
|
3181
|
+
userMessage: message === null ? null : message.freshness ?? "current",
|
|
3182
|
+
originalUserTask: context.originalUserTask?.origin ?? null,
|
|
3183
|
+
delegatedTask: context.delegatedTask !== null
|
|
3184
|
+
};
|
|
3185
|
+
}
|
|
3162
3186
|
//#endregion
|
|
3163
3187
|
//#region src/diagnostics/write-judge-usage.ts
|
|
3164
3188
|
async function writeJudgeUsage(usage, host, warnings) {
|
|
@@ -3946,6 +3970,31 @@ async function classifyWithJudge(payload, evidence, judge, options) {
|
|
|
3946
3970
|
});
|
|
3947
3971
|
}
|
|
3948
3972
|
//#endregion
|
|
3973
|
+
//#region src/model/build-budget-omitted-context.ts
|
|
3974
|
+
function buildBudgetOmittedContext(context, field) {
|
|
3975
|
+
return {
|
|
3976
|
+
...context,
|
|
3977
|
+
[field]: null,
|
|
3978
|
+
omittedTaskContext: [...context.omittedTaskContext.filter((item) => item.field !== field), {
|
|
3979
|
+
field,
|
|
3980
|
+
reason: "budget"
|
|
3981
|
+
}]
|
|
3982
|
+
};
|
|
3983
|
+
}
|
|
3984
|
+
//#endregion
|
|
3985
|
+
//#region src/model/build-task-context.ts
|
|
3986
|
+
function buildTaskContext(context) {
|
|
3987
|
+
let result = {
|
|
3988
|
+
...context,
|
|
3989
|
+
omittedTaskContext: [...context.omittedTaskContext]
|
|
3990
|
+
};
|
|
3991
|
+
for (const field of ["originalUserTask", "delegatedTask"]) {
|
|
3992
|
+
const task = result[field];
|
|
3993
|
+
if (task !== null && Buffer.byteLength(task.text) > 4096) result = buildBudgetOmittedContext(result, field);
|
|
3994
|
+
}
|
|
3995
|
+
return result;
|
|
3996
|
+
}
|
|
3997
|
+
//#endregion
|
|
3949
3998
|
//#region src/model/build-task-scope-summary.ts
|
|
3950
3999
|
function buildTaskScopeSummary(scope) {
|
|
3951
4000
|
return {
|
|
@@ -4230,31 +4279,6 @@ function resolveHooksPath(path, worktree, home) {
|
|
|
4230
4279
|
return path.startsWith("~/") ? join(home, path.slice(2)) : resolve(worktree, path);
|
|
4231
4280
|
}
|
|
4232
4281
|
//#endregion
|
|
4233
|
-
//#region src/model/build-budget-omitted-context.ts
|
|
4234
|
-
function buildBudgetOmittedContext(context, field) {
|
|
4235
|
-
return {
|
|
4236
|
-
...context,
|
|
4237
|
-
[field]: null,
|
|
4238
|
-
omittedTaskContext: [...context.omittedTaskContext.filter((item) => item.field !== field), {
|
|
4239
|
-
field,
|
|
4240
|
-
reason: "budget"
|
|
4241
|
-
}]
|
|
4242
|
-
};
|
|
4243
|
-
}
|
|
4244
|
-
//#endregion
|
|
4245
|
-
//#region src/model/build-task-context.ts
|
|
4246
|
-
function buildTaskContext(context) {
|
|
4247
|
-
let result = {
|
|
4248
|
-
...context,
|
|
4249
|
-
omittedTaskContext: [...context.omittedTaskContext]
|
|
4250
|
-
};
|
|
4251
|
-
for (const field of ["originalUserTask", "delegatedTask"]) {
|
|
4252
|
-
const task = result[field];
|
|
4253
|
-
if (task !== null && Buffer.byteLength(task.text) > 4096) result = buildBudgetOmittedContext(result, field);
|
|
4254
|
-
}
|
|
4255
|
-
return result;
|
|
4256
|
-
}
|
|
4257
|
-
//#endregion
|
|
4258
4282
|
//#region src/git/parse-config-parameters.ts
|
|
4259
4283
|
function parseConfigParameters(text) {
|
|
4260
4284
|
const parameters = [];
|
|
@@ -4798,6 +4822,7 @@ function buildDecisionRequest(payload, policy, options) {
|
|
|
4798
4822
|
const rulesSource = options.rulesSource ?? "replacement";
|
|
4799
4823
|
const repositoryContext = options.repositoryContext ?? null;
|
|
4800
4824
|
const mcpServers = options.mcpServers ?? [];
|
|
4825
|
+
const exemptRules = options.exemptRules ?? [];
|
|
4801
4826
|
const rules = {};
|
|
4802
4827
|
let tier = null;
|
|
4803
4828
|
for (const section of policy.split(/(?=^## |^### )/mu)) if (section.startsWith("## HARD BLOCK rules")) tier = "hard";
|
|
@@ -4808,6 +4833,7 @@ function buildDecisionRequest(payload, policy, options) {
|
|
|
4808
4833
|
const end = newline === -1 ? section.length : newline;
|
|
4809
4834
|
const name = section.slice(4, end).trim();
|
|
4810
4835
|
if (name === "" || Object.values(rules).some((rule) => rule.name === name)) throw new Error("Policy has an empty or duplicate rule");
|
|
4836
|
+
if (rulesSource === "shipped" && exemptRules.includes(name)) continue;
|
|
4811
4837
|
rules[`rule_${Object.keys(rules).length}`] = {
|
|
4812
4838
|
name,
|
|
4813
4839
|
tier,
|
|
@@ -5033,6 +5059,30 @@ function classifyFailure(attempt, timeoutMs) {
|
|
|
5033
5059
|
};
|
|
5034
5060
|
}
|
|
5035
5061
|
//#endregion
|
|
5062
|
+
//#region src/model/build-sized-decision-input.ts
|
|
5063
|
+
function buildSizedDecisionInput(model, request) {
|
|
5064
|
+
return buildFittedInput(buildFittedInput(buildInput(model, request.state, request.questions), "delegatedTask"), "originalUserTask");
|
|
5065
|
+
}
|
|
5066
|
+
function buildInput(model, state, questions) {
|
|
5067
|
+
const input = {
|
|
5068
|
+
model,
|
|
5069
|
+
state,
|
|
5070
|
+
questions
|
|
5071
|
+
};
|
|
5072
|
+
return {
|
|
5073
|
+
input,
|
|
5074
|
+
body: JSON.stringify(input)
|
|
5075
|
+
};
|
|
5076
|
+
}
|
|
5077
|
+
function buildFittedInput(sized, field) {
|
|
5078
|
+
const context = sized.input.state.taskContext;
|
|
5079
|
+
if (Buffer.byteLength(sized.body) <= 1e5 || context === void 0 || context[field] === null) return sized;
|
|
5080
|
+
return buildInput(sized.input.model, {
|
|
5081
|
+
...sized.input.state,
|
|
5082
|
+
taskContext: buildBudgetOmittedContext(context, field)
|
|
5083
|
+
}, sized.input.questions);
|
|
5084
|
+
}
|
|
5085
|
+
//#endregion
|
|
5036
5086
|
//#region src/model/collect-config-file-paths.ts
|
|
5037
5087
|
function collectConfigFilePaths(command) {
|
|
5038
5088
|
const values = splitShellCommand(command).segments.flatMap((segment) => splitShellTokens(segment.text).tokens.flatMap((token) => toWordValues(token))).flatMap((word) => {
|
|
@@ -5069,18 +5119,7 @@ function buildDecisionResponseSchema(choices) {
|
|
|
5069
5119
|
//#endregion
|
|
5070
5120
|
//#region src/model/send-decision.ts
|
|
5071
5121
|
async function sendDecision(provider, apiKey, request, options) {
|
|
5072
|
-
const
|
|
5073
|
-
model: provider.model,
|
|
5074
|
-
state: { ...request.state },
|
|
5075
|
-
questions: request.questions
|
|
5076
|
-
};
|
|
5077
|
-
let body = JSON.stringify(input);
|
|
5078
|
-
for (const field of ["delegatedTask", "originalUserTask"]) {
|
|
5079
|
-
const context = input.state.taskContext;
|
|
5080
|
-
if (Buffer.byteLength(body) <= 1e5 || context === void 0 || context[field] === null) continue;
|
|
5081
|
-
input.state.taskContext = buildBudgetOmittedContext(context, field);
|
|
5082
|
-
body = JSON.stringify(input);
|
|
5083
|
-
}
|
|
5122
|
+
const body = buildSizedDecisionInput(provider.model, request).body;
|
|
5084
5123
|
const requestBytes = Buffer.byteLength(body);
|
|
5085
5124
|
if (requestBytes > 1e5) throw new DecisionRequestError("request-too-large", requestBytes, "Decision input exceeds 100000 bytes; refusing to truncate the action or user message");
|
|
5086
5125
|
let response;
|
|
@@ -5165,7 +5204,8 @@ async function classifyWithJev(payload, config, options) {
|
|
|
5165
5204
|
repositoryContext,
|
|
5166
5205
|
mcpServers,
|
|
5167
5206
|
localHookConfig,
|
|
5168
|
-
hookFacts
|
|
5207
|
+
hookFacts,
|
|
5208
|
+
exemptRules: options.exemptRules
|
|
5169
5209
|
});
|
|
5170
5210
|
const signal = createDeadlineSignal(config.provider.timeoutMs, options);
|
|
5171
5211
|
if (signal === null) throw new DOMException("Evaluation deadline expired", "AbortError");
|
|
@@ -5175,6 +5215,7 @@ async function classifyWithJev(payload, config, options) {
|
|
|
5175
5215
|
fetch: runtime.fetch
|
|
5176
5216
|
});
|
|
5177
5217
|
stage = "response";
|
|
5218
|
+
options.onTaskContext?.(buildSizedDecisionInput(config.provider.model, request).input.state.taskContext);
|
|
5178
5219
|
return buildJevOutcome({
|
|
5179
5220
|
kind: "reply",
|
|
5180
5221
|
request,
|
|
@@ -5981,31 +6022,65 @@ async function probeLauncherSpawner(location, readTextFile) {
|
|
|
5981
6022
|
//#region src/scope/resolve-opening-prompt.ts
|
|
5982
6023
|
async function resolveOpeningPrompt(request, runtime) {
|
|
5983
6024
|
const context = request.decisionContext;
|
|
5984
|
-
const
|
|
5985
|
-
|
|
5986
|
-
const
|
|
6025
|
+
const task = context?.originalUserTask ?? null;
|
|
6026
|
+
const message = context?.lastDirectUserMessage ?? null;
|
|
6027
|
+
const opening = task?.position === "opening" ? task : message;
|
|
6028
|
+
if (context === void 0 || opening?.position !== "opening") return request;
|
|
5987
6029
|
const isSpawned = await probeLauncherSpawner(runtime.host.env["AUTO_MODE_SCOPE_FILE"], runtime.readTextFile);
|
|
5988
6030
|
return {
|
|
5989
6031
|
...request,
|
|
5990
|
-
decisionContext: {
|
|
6032
|
+
decisionContext: isSpawned ? buildSpawnedContext(context, opening.text) : {
|
|
5991
6033
|
...context,
|
|
5992
|
-
|
|
6034
|
+
originalUserTask: task === null ? null : toUnmarked(task),
|
|
6035
|
+
lastDirectUserMessage: message === null ? null : toUnmarked(message)
|
|
5993
6036
|
}
|
|
5994
6037
|
};
|
|
5995
6038
|
}
|
|
6039
|
+
function buildSpawnedContext(context, openingText) {
|
|
6040
|
+
const isTaskOpening = context.originalUserTask?.position === "opening";
|
|
6041
|
+
const message = context.lastDirectUserMessage;
|
|
6042
|
+
const isOmitted = context.omittedTaskContext.some((omission) => omission.field === "originalUserTask");
|
|
6043
|
+
return {
|
|
6044
|
+
...context,
|
|
6045
|
+
originalUserTask: isTaskOpening ? null : context.originalUserTask,
|
|
6046
|
+
delegatedTask: context.agentID === null ? context.delegatedTask ?? {
|
|
6047
|
+
text: openingText,
|
|
6048
|
+
origin: "agent.spawn"
|
|
6049
|
+
} : context.delegatedTask,
|
|
6050
|
+
lastDirectUserMessage: message?.position === "opening" ? null : message,
|
|
6051
|
+
omittedTaskContext: isTaskOpening && !isOmitted ? [...context.omittedTaskContext, {
|
|
6052
|
+
field: "originalUserTask",
|
|
6053
|
+
reason: "unavailable"
|
|
6054
|
+
}] : context.omittedTaskContext
|
|
6055
|
+
};
|
|
6056
|
+
}
|
|
6057
|
+
function toUnmarked(value) {
|
|
6058
|
+
const { position: _, ...unmarked } = value;
|
|
6059
|
+
return unmarked;
|
|
6060
|
+
}
|
|
5996
6061
|
//#endregion
|
|
5997
6062
|
//#region src/classify-action.ts
|
|
5998
6063
|
async function classifyAction(request, config, options) {
|
|
5999
|
-
const stderr = options.stderr;
|
|
6000
|
-
const host = options.runtime.host;
|
|
6001
6064
|
const invocationID = randomUUID();
|
|
6002
|
-
if (options.actionLog === true) await writeActionDiagnostic(request, {
|
|
6003
|
-
invocationID,
|
|
6004
|
-
status: "started"
|
|
6005
|
-
}, host, stderr);
|
|
6006
6065
|
const resolved = await resolveOpeningPrompt(request, options.runtime);
|
|
6007
|
-
const
|
|
6008
|
-
if (options.actionLog === true) await writeActionDiagnostic(
|
|
6066
|
+
const offered = resolved.decisionContext === void 0 ? void 0 : buildTaskContext(resolved.decisionContext);
|
|
6067
|
+
if (options.actionLog === true) await writeActionDiagnostic(resolved, {
|
|
6068
|
+
invocationID,
|
|
6069
|
+
status: "started",
|
|
6070
|
+
taskContext: offered
|
|
6071
|
+
}, options.runtime.host, options.stderr);
|
|
6072
|
+
const received = { context: offered };
|
|
6073
|
+
const onTaskContext = (context) => {
|
|
6074
|
+
received.context = context;
|
|
6075
|
+
};
|
|
6076
|
+
const outcome = options.budget === true ? await classifyWithBudget(resolved, config, {
|
|
6077
|
+
...options,
|
|
6078
|
+
onTaskContext
|
|
6079
|
+
}) : await classifyStages(resolved, config, {
|
|
6080
|
+
...options,
|
|
6081
|
+
onTaskContext
|
|
6082
|
+
});
|
|
6083
|
+
if (options.actionLog === true) await writeActionDiagnostic(resolved, {
|
|
6009
6084
|
invocationID,
|
|
6010
6085
|
status: outcome.status,
|
|
6011
6086
|
verdict: outcome.verdict?.kind ?? "defer",
|
|
@@ -6014,8 +6089,9 @@ async function classifyAction(request, config, options) {
|
|
|
6014
6089
|
...outcome.escalation === void 0 ? {} : { escalation: outcome.escalation },
|
|
6015
6090
|
...outcome.diagnostics === void 0 ? {} : { diagnostics: outcome.diagnostics },
|
|
6016
6091
|
...outcome.judge === void 0 ? {} : { judge: outcome.judge },
|
|
6017
|
-
...outcome.grant === void 0 ? {} : { grant: outcome.grant }
|
|
6018
|
-
|
|
6092
|
+
...outcome.grant === void 0 ? {} : { grant: outcome.grant },
|
|
6093
|
+
taskContext: received.context
|
|
6094
|
+
}, options.runtime.host, options.stderr);
|
|
6019
6095
|
return outcome;
|
|
6020
6096
|
}
|
|
6021
6097
|
async function classifyWithBudget(request, config, options) {
|
|
@@ -6052,7 +6128,8 @@ async function classifyStages(request, config, options) {
|
|
|
6052
6128
|
local: { kind: "escalate" },
|
|
6053
6129
|
checkout: null,
|
|
6054
6130
|
scope: null,
|
|
6055
|
-
grant: null
|
|
6131
|
+
grant: null,
|
|
6132
|
+
exemptRules: []
|
|
6056
6133
|
};
|
|
6057
6134
|
const reviewed = await classifyWithGrant(ctx, await runStages(ctx));
|
|
6058
6135
|
if (reviewed.verdict?.kind !== "deny") return reviewed;
|
|
@@ -6236,9 +6313,12 @@ async function classifyEditBypass(ctx) {
|
|
|
6236
6313
|
};
|
|
6237
6314
|
}
|
|
6238
6315
|
async function classifyReplyChannel(ctx) {
|
|
6239
|
-
const
|
|
6240
|
-
if (
|
|
6241
|
-
|
|
6316
|
+
const reply = await classifyReplyCall(ctx.request, ctx.scope, ctx.hasConfiguredDenies);
|
|
6317
|
+
if (reply.kind !== "bypass") return {
|
|
6318
|
+
kind: "pass",
|
|
6319
|
+
facts: { exemptRules: reply.kind === "exempt" ? reply.rules : [] }
|
|
6320
|
+
};
|
|
6321
|
+
const channel = reply.channel;
|
|
6242
6322
|
return {
|
|
6243
6323
|
kind: "decided",
|
|
6244
6324
|
outcome: {
|
|
@@ -6267,7 +6347,8 @@ async function classifyJev(ctx) {
|
|
|
6267
6347
|
taskScope: ctx.scope === null ? void 0 : buildTaskScopeSummary(ctx.scope),
|
|
6268
6348
|
claudeSettings: ctx.claudeSettings,
|
|
6269
6349
|
checkout: ctx.checkout ?? void 0,
|
|
6270
|
-
readCheckout: ctx.readCheckout
|
|
6350
|
+
readCheckout: ctx.readCheckout,
|
|
6351
|
+
exemptRules: ctx.exemptRules
|
|
6271
6352
|
});
|
|
6272
6353
|
return {
|
|
6273
6354
|
...outcome,
|
|
@@ -6359,12 +6440,12 @@ const userTaskSchema = strictObject({
|
|
|
6359
6440
|
"composer",
|
|
6360
6441
|
"bridge",
|
|
6361
6442
|
"sdk"
|
|
6362
|
-
])
|
|
6443
|
+
]),
|
|
6444
|
+
position: literal("opening").optional()
|
|
6363
6445
|
});
|
|
6364
6446
|
const directUserMessageSchema = strictObject({
|
|
6365
6447
|
...userTaskSchema.shape,
|
|
6366
|
-
freshness: literal("stale").optional()
|
|
6367
|
-
position: literal("opening").optional()
|
|
6448
|
+
freshness: literal("stale").optional()
|
|
6368
6449
|
});
|
|
6369
6450
|
const delegatedTaskSchema = strictObject({
|
|
6370
6451
|
text: string(),
|
|
@@ -5,11 +5,11 @@ export type MessageOrigin = (typeof MESSAGE_ORIGINS)[number];
|
|
|
5
5
|
export interface UserTask {
|
|
6
6
|
readonly text: string;
|
|
7
7
|
readonly origin: MessageOrigin;
|
|
8
|
+
readonly position?: 'opening' | undefined;
|
|
8
9
|
}
|
|
9
10
|
|
|
10
11
|
export interface DirectUserMessage extends UserTask {
|
|
11
12
|
readonly freshness?: 'stale' | undefined;
|
|
12
|
-
readonly position?: 'opening' | undefined;
|
|
13
13
|
}
|
|
14
14
|
|
|
15
15
|
interface DelegatedTask {
|
|
@@ -36,13 +36,16 @@ export function buildPromptContext(
|
|
|
36
36
|
};
|
|
37
37
|
}
|
|
38
38
|
|
|
39
|
-
const message: UserTask = { text: input.text, origin };
|
|
40
39
|
const isOpeningPrompt = previous?.awaitsOpeningPrompt ?? true;
|
|
41
40
|
|
|
41
|
+
const message: UserTask = isOpeningPrompt
|
|
42
|
+
? { text: input.text, origin, position: 'opening' }
|
|
43
|
+
: { text: input.text, origin };
|
|
44
|
+
|
|
42
45
|
return {
|
|
43
46
|
originalUserTask:
|
|
44
47
|
previous?.originalUserTask ?? (previous?.canCaptureOriginal === true ? message : null),
|
|
45
|
-
lastDirectUserMessage:
|
|
48
|
+
lastDirectUserMessage: message,
|
|
46
49
|
canCaptureOriginal: previous?.canCaptureOriginal ?? false,
|
|
47
50
|
awaitsOpeningPrompt: false,
|
|
48
51
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "auto-mode",
|
|
3
|
-
"version": "3.1.
|
|
3
|
+
"version": "3.1.5",
|
|
4
4
|
"description": "A permission classifier library and Claude Code mod, so agents that are not Claude can run unattended",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"agent",
|
|
@@ -52,6 +52,7 @@
|
|
|
52
52
|
"eval:question-shape": "bun --no-env-file --conditions=auto-mode-eval evals/runners/run-question-shape-evaluation.ts",
|
|
53
53
|
"eval:relay-consent": "bun --no-env-file --conditions=auto-mode-eval evals/runners/run-relay-consent-evaluation.ts",
|
|
54
54
|
"eval:second-judge": "bun --no-env-file --conditions=auto-mode-eval evals/runners/run-second-judge-evaluation.ts",
|
|
55
|
+
"eval:spawned-task": "bun --no-env-file --conditions=auto-mode-eval evals/runners/run-spawned-task-evaluation.ts",
|
|
55
56
|
"eval:stale-consent": "bun --no-env-file --conditions=auto-mode-eval evals/runners/run-stale-consent-evaluation.ts",
|
|
56
57
|
"format": "oxfmt . && format-codemod --quiet .",
|
|
57
58
|
"format:check": "oxfmt --check . && format-codemod --check --quiet .",
|