opencode-shell-safety 0.3.0 → 0.4.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 CHANGED
@@ -78,6 +78,7 @@ Get an API key from [TypeSafe AI](https://docs.typesafe.ai/introduction/quicksta
78
78
  | `cache.capacity` | Maximum number of cached classification results. |
79
79
  | `cache.ttlMs` | Successful classification cache lifetime in milliseconds. |
80
80
  | `agents.<name>.enabled` | Enables classification for an agent. |
81
+ | `agents.<name>.fallback` | Optional. Effect applied when classification rejects the command or the request fails: `ask` or `deny`. Defaults to `deny`. |
81
82
  | `agents.<name>.thresholds` | Optional per-agent probability thresholds. |
82
83
  | `agents.<name>.http` | Optional. Omission permits no HTTP methods or credential hosts. |
83
84
  | `agents.<name>.http.methods` | HTTP methods the policy permits. |
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "opencode-shell-safety",
3
- "version": "0.3.0",
3
+ "version": "0.4.0",
4
4
  "description": "OpenCode plugin that classifies shell permission requests against agent policy.",
5
5
  "license": "MIT",
6
6
  "type": "module",
package/src/index.ts CHANGED
@@ -33,6 +33,8 @@ const ThresholdsSchema = Schema.Struct({
33
33
  violationProbability: Probability,
34
34
  })
35
35
 
36
+ const FallbackEffectSchema = Schema.Literals(["ask", "deny"])
37
+
36
38
  const HttpPolicySchema = Schema.Struct({
37
39
  methods: Schema.Array(Schema.String).pipe(Schema.withDecodingDefaultKey(Effect.succeed([]))),
38
40
  credentials: Schema.Record(Schema.String, Schema.Array(Schema.String))
@@ -41,6 +43,7 @@ const HttpPolicySchema = Schema.Struct({
41
43
 
42
44
  const AgentPolicySchema = Schema.Struct({
43
45
  enabled: Schema.Boolean,
46
+ fallback: Schema.optionalKey(FallbackEffectSchema),
44
47
  thresholds: Schema.optionalKey(ThresholdsSchema),
45
48
  http: HttpPolicySchema.pipe(Schema.withDecodingDefaultKey(Effect.succeed({ methods: [], credentials: {} }))),
46
49
  })
@@ -75,6 +78,7 @@ export const OptionsSchema = Schema.Struct({
75
78
 
76
79
  export type Options = typeof OptionsSchema.Type
77
80
  export type AgentPolicy = typeof AgentPolicySchema.Type
81
+ export type FallbackEffect = typeof FallbackEffectSchema.Type
78
82
  export type Thresholds = typeof ThresholdsSchema.Type
79
83
 
80
84
  const NoulAnswerSchema = Schema.Struct({
@@ -174,8 +178,7 @@ export const permissionFromAssessment = (
174
178
  return assessment.withinPolicy.noul >= thresholds.allowProbability && !hasViolation ? "allow" : "deny"
175
179
  }
176
180
 
177
- export const fallbackEffect = (configured: PermissionEffect): PermissionEffect =>
178
- configured === "allow" ? "deny" : configured
181
+ export const fallbackEffect = (fallback: FallbackEffect | undefined): PermissionEffect => fallback ?? "deny"
179
182
 
180
183
  const noulQuestion = (instructions: string, yes: string, no: string): NoulQuestion => ({
181
184
  type: "noul",
@@ -448,7 +451,7 @@ export const createPermissionEvaluator = (
448
451
  const policy = findPolicy(options, agent)
449
452
  if (!policy?.enabled) return Effect.void
450
453
  const classifiedEvent = { ...event, agent }
451
- const fallback = fallbackEffect(event.effect)
454
+ const fallback = fallbackEffect(policy.fallback)
452
455
 
453
456
  return Effect.gen(function* () {
454
457
  if (!projectDirectory) {