opencode-swarm 7.7.0 → 7.8.1
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 +3 -1
- package/dist/agents/index.d.ts +11 -3
- package/dist/cli/index.js +788 -358
- package/dist/commands/full-auto.d.ts +13 -2
- package/dist/config/evidence-schema.d.ts +3 -3
- package/dist/config/schema.d.ts +82 -9
- package/dist/full-auto/cadence.d.ts +64 -0
- package/dist/full-auto/input-probe.d.ts +22 -0
- package/dist/full-auto/oversight.d.ts +93 -0
- package/dist/full-auto/phase-approval.d.ts +7 -0
- package/dist/full-auto/policy.d.ts +85 -0
- package/dist/full-auto/state.d.ts +121 -0
- package/dist/hooks/full-auto-delegation.d.ts +28 -0
- package/dist/hooks/full-auto-input-probe.d.ts +27 -0
- package/dist/hooks/full-auto-intercept.d.ts +1 -1
- package/dist/hooks/full-auto-permission.d.ts +39 -0
- package/dist/hooks/index.d.ts +1 -1
- package/dist/hooks/utils.d.ts +40 -0
- package/dist/index.js +4014 -1267
- package/dist/lang/runtime.d.ts +10 -0
- package/dist/state.d.ts +8 -0
- package/package.json +1 -1
|
@@ -2,9 +2,20 @@
|
|
|
2
2
|
* Handles the /swarm full-auto command.
|
|
3
3
|
* Toggles Full-Auto Mode on or off for the active session.
|
|
4
4
|
*
|
|
5
|
-
*
|
|
5
|
+
* In Full-Auto v2 this also creates a durable run-state record under
|
|
6
|
+
* .swarm/full-auto-state.json so the permission/oversight infrastructure can
|
|
7
|
+
* fail-closed across hooks and across process restarts.
|
|
8
|
+
*
|
|
9
|
+
* H2 fix: durable write happens BEFORE flipping the legacy
|
|
10
|
+
* `session.fullAutoMode` flag. If the durable write fails, the command
|
|
11
|
+
* surfaces the error in its return string and does NOT enable the legacy
|
|
12
|
+
* reactive intercept — preventing a silent fail-open where reactive checks
|
|
13
|
+
* would believe Full-Auto is on while the v2 permission hook sees no
|
|
14
|
+
* durable run.
|
|
15
|
+
*
|
|
16
|
+
* @param directory - Project directory (used to persist Full-Auto run state)
|
|
6
17
|
* @param args - Optional argument: "on" | "off" | undefined (toggle behavior)
|
|
7
18
|
* @param sessionID - Session ID for accessing active session state
|
|
8
19
|
* @returns Feedback message about Full-Auto Mode state
|
|
9
20
|
*/
|
|
10
|
-
export declare function handleFullAutoCommand(
|
|
21
|
+
export declare function handleFullAutoCommand(directory: string, args: string[], sessionID: string): Promise<string>;
|
|
@@ -205,9 +205,9 @@ export declare const RetrospectiveEvidenceSchema: z.ZodObject<{
|
|
|
205
205
|
other: "other";
|
|
206
206
|
}>;
|
|
207
207
|
scope: z.ZodEnum<{
|
|
208
|
-
project: "project";
|
|
209
208
|
global: "global";
|
|
210
209
|
session: "session";
|
|
210
|
+
project: "project";
|
|
211
211
|
}>;
|
|
212
212
|
}, z.core.$strip>>>;
|
|
213
213
|
approaches_tried: z.ZodDefault<z.ZodArray<z.ZodObject<{
|
|
@@ -651,9 +651,9 @@ export declare const EvidenceSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
|
651
651
|
other: "other";
|
|
652
652
|
}>;
|
|
653
653
|
scope: z.ZodEnum<{
|
|
654
|
-
project: "project";
|
|
655
654
|
global: "global";
|
|
656
655
|
session: "session";
|
|
656
|
+
project: "project";
|
|
657
657
|
}>;
|
|
658
658
|
}, z.core.$strip>>>;
|
|
659
659
|
approaches_tried: z.ZodDefault<z.ZodArray<z.ZodObject<{
|
|
@@ -1070,9 +1070,9 @@ export declare const EvidenceBundleSchema: z.ZodObject<{
|
|
|
1070
1070
|
other: "other";
|
|
1071
1071
|
}>;
|
|
1072
1072
|
scope: z.ZodEnum<{
|
|
1073
|
-
project: "project";
|
|
1074
1073
|
global: "global";
|
|
1075
1074
|
session: "session";
|
|
1075
|
+
project: "project";
|
|
1076
1076
|
}>;
|
|
1077
1077
|
}, z.core.$strip>>>;
|
|
1078
1078
|
approaches_tried: z.ZodDefault<z.ZodArray<z.ZodObject<{
|
package/dist/config/schema.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
|
+
import { type AgentName } from './constants';
|
|
2
3
|
/**
|
|
3
4
|
* Test-only dependency-injection seam — see `gitignore-warning.ts:_internals`
|
|
4
5
|
* for the rationale (`mock.module` from `bun:test` leaks across files in
|
|
@@ -7,21 +8,62 @@ import { z } from 'zod';
|
|
|
7
8
|
*/
|
|
8
9
|
export declare const _internals: {
|
|
9
10
|
stripKnownSwarmPrefix: typeof stripKnownSwarmPrefix;
|
|
11
|
+
getCanonicalAgentRole: typeof getCanonicalAgentRole;
|
|
10
12
|
resolveGuardrailsConfig: typeof resolveGuardrailsConfig;
|
|
11
13
|
};
|
|
12
14
|
/**
|
|
13
|
-
*
|
|
15
|
+
* Type guard: returns true when `role` is a canonical agent role recognized
|
|
16
|
+
* by the plugin (e.g. "architect", "coder", "critic_oversight"). User-defined
|
|
17
|
+
* swarm IDs must NOT be treated as canonical roles.
|
|
18
|
+
*/
|
|
19
|
+
export declare function isKnownCanonicalRole(role: string): role is AgentName;
|
|
20
|
+
/**
|
|
21
|
+
* Extract the canonical agent role from a generated agent name, using
|
|
22
|
+
* suffix-based matching with longest-suffix-wins.
|
|
23
|
+
*
|
|
24
|
+
* Generated agent names have the shape `<arbitrary user-defined swarm ID>
|
|
25
|
+
* <separator> <canonical role>`. The swarm ID is opaque to the plugin —
|
|
26
|
+
* it can be anything the user configures (e.g. `banana`, `acme-prod`,
|
|
27
|
+
* `customer123`). Only the canonical role suffix is plugin-defined.
|
|
28
|
+
*
|
|
29
|
+
* Behavior:
|
|
30
|
+
* - If `agentName` is itself a canonical role, return it unchanged.
|
|
31
|
+
* - Else, find the longest canonical role `R` such that `agentName`
|
|
32
|
+
* ends with `<sep><R>` for some separator in {"_", "-", " "}; return `R`.
|
|
33
|
+
* - Else, return `agentName` unchanged (caller can detect "no role found"
|
|
34
|
+
* by comparing the result to `agentName`, or by passing the result
|
|
35
|
+
* through `isKnownCanonicalRole`).
|
|
14
36
|
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
37
|
+
* Optional `generatedAgentNames` argument: when supplied (e.g. from
|
|
38
|
+
* `getAgentConfigs` output at plugin init), the function ONLY infers a role
|
|
39
|
+
* for names actually present in that registry. Bare user-supplied strings
|
|
40
|
+
* like `not_an_architect` are NOT treated as roles unless they appear in
|
|
41
|
+
* the generated-name set. Callers that need this strict behavior should
|
|
42
|
+
* use `resolveGeneratedAgentRole` instead.
|
|
19
43
|
*
|
|
20
|
-
*
|
|
21
|
-
*
|
|
44
|
+
* Case-insensitive on the input; the returned role is the canonical
|
|
45
|
+
* lowercase form from `ALL_AGENT_NAMES`.
|
|
46
|
+
*/
|
|
47
|
+
export declare function getCanonicalAgentRole(agentName: string, generatedAgentNames?: Iterable<string>): AgentName | string;
|
|
48
|
+
/**
|
|
49
|
+
* Strict variant of {@link getCanonicalAgentRole}: only infers a canonical
|
|
50
|
+
* role when the agent name is actually present in the supplied generated-
|
|
51
|
+
* name registry, OR is itself a canonical role. Use this from callers that
|
|
52
|
+
* must avoid treating arbitrary user-supplied strings as roles.
|
|
53
|
+
*/
|
|
54
|
+
export declare function resolveGeneratedAgentRole(agentName: string, generatedAgentNames: Iterable<string>): AgentName | string;
|
|
55
|
+
/**
|
|
56
|
+
* Backward-compatible alias for {@link getCanonicalAgentRole}. The previous
|
|
57
|
+
* implementation stripped a hardcoded list of "known swarm prefixes" from
|
|
58
|
+
* the front of the agent name. That approach was wrong by design: swarm
|
|
59
|
+
* IDs are arbitrary user-defined strings — the plugin cannot enumerate
|
|
60
|
+
* them. The new implementation does suffix-based canonical role extraction
|
|
61
|
+
* (see `getCanonicalAgentRole`) which works for ANY user-defined swarm ID.
|
|
22
62
|
*
|
|
23
|
-
*
|
|
24
|
-
*
|
|
63
|
+
* Existing tests that pass `synthetic_reviewer` / `mega_architect` /
|
|
64
|
+
* `cloud_critic_oversight` / etc. continue to pass because those names
|
|
65
|
+
* end with `<sep><canonical role>`, which is exactly what the suffix
|
|
66
|
+
* extractor matches.
|
|
25
67
|
*/
|
|
26
68
|
export declare function stripKnownSwarmPrefix(agentName: string): string;
|
|
27
69
|
export declare const AgentOverrideConfigSchema: z.ZodObject<{
|
|
@@ -1073,6 +1115,37 @@ export declare const PluginConfigSchema: z.ZodObject<{
|
|
|
1073
1115
|
pause: "pause";
|
|
1074
1116
|
terminate: "terminate";
|
|
1075
1117
|
}>>;
|
|
1118
|
+
mode: z.ZodDefault<z.ZodEnum<{
|
|
1119
|
+
strict: "strict";
|
|
1120
|
+
assisted: "assisted";
|
|
1121
|
+
supervised: "supervised";
|
|
1122
|
+
}>>;
|
|
1123
|
+
fail_closed: z.ZodDefault<z.ZodBoolean>;
|
|
1124
|
+
permission_policy: z.ZodDefault<z.ZodObject<{
|
|
1125
|
+
enabled: z.ZodDefault<z.ZodBoolean>;
|
|
1126
|
+
trusted_roots: z.ZodDefault<z.ZodArray<z.ZodString>>;
|
|
1127
|
+
trusted_domains: z.ZodDefault<z.ZodArray<z.ZodString>>;
|
|
1128
|
+
protected_paths: z.ZodDefault<z.ZodArray<z.ZodString>>;
|
|
1129
|
+
allow_defaults: z.ZodDefault<z.ZodBoolean>;
|
|
1130
|
+
}, z.core.$strip>>;
|
|
1131
|
+
denials: z.ZodDefault<z.ZodObject<{
|
|
1132
|
+
max_consecutive: z.ZodDefault<z.ZodNumber>;
|
|
1133
|
+
max_total: z.ZodDefault<z.ZodNumber>;
|
|
1134
|
+
on_limit: z.ZodDefault<z.ZodEnum<{
|
|
1135
|
+
pause: "pause";
|
|
1136
|
+
terminate: "terminate";
|
|
1137
|
+
}>>;
|
|
1138
|
+
}, z.core.$strip>>;
|
|
1139
|
+
oversight: z.ZodDefault<z.ZodObject<{
|
|
1140
|
+
on_plan_change: z.ZodDefault<z.ZodBoolean>;
|
|
1141
|
+
on_task_completion: z.ZodDefault<z.ZodBoolean>;
|
|
1142
|
+
on_phase_boundary: z.ZodDefault<z.ZodBoolean>;
|
|
1143
|
+
on_high_risk_action: z.ZodDefault<z.ZodBoolean>;
|
|
1144
|
+
on_subagent_return_warning: z.ZodDefault<z.ZodBoolean>;
|
|
1145
|
+
every_tool_calls: z.ZodDefault<z.ZodNumber>;
|
|
1146
|
+
every_architect_turns: z.ZodDefault<z.ZodNumber>;
|
|
1147
|
+
every_minutes: z.ZodDefault<z.ZodNumber>;
|
|
1148
|
+
}, z.core.$strip>>;
|
|
1076
1149
|
}, z.core.$strip>>>;
|
|
1077
1150
|
}, z.core.$strip>;
|
|
1078
1151
|
export type PluginConfig = z.infer<typeof PluginConfigSchema>;
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Full-Auto v2 oversight cadence.
|
|
3
|
+
*
|
|
4
|
+
* Pure helpers that decide when periodic / risk-triggered oversight should
|
|
5
|
+
* fire. Wired into the existing tool.execute.after flow (counters increment)
|
|
6
|
+
* and into the chat.message transform (architect turn increment) by the
|
|
7
|
+
* orchestrating hook composition in `src/index.ts`.
|
|
8
|
+
*
|
|
9
|
+
* Critic oversight sessions and critic-internal tool calls must be exempt
|
|
10
|
+
* from triggering further Full-Auto oversight. Callers identify those by
|
|
11
|
+
* passing `excludeAgent: true` for the relevant call.
|
|
12
|
+
*/
|
|
13
|
+
import type { PluginConfig } from '../config';
|
|
14
|
+
import { dispatchFullAutoOversight } from './oversight';
|
|
15
|
+
import { type FullAutoRunState } from './state';
|
|
16
|
+
export type CadenceTrigger = {
|
|
17
|
+
kind: 'tool_calls';
|
|
18
|
+
threshold: number;
|
|
19
|
+
} | {
|
|
20
|
+
kind: 'architect_turns';
|
|
21
|
+
threshold: number;
|
|
22
|
+
} | {
|
|
23
|
+
kind: 'minutes';
|
|
24
|
+
threshold: number;
|
|
25
|
+
elapsedMinutes: number;
|
|
26
|
+
} | {
|
|
27
|
+
kind: 'consecutive_no_progress';
|
|
28
|
+
threshold: number;
|
|
29
|
+
} | {
|
|
30
|
+
kind: 'denials_near_limit';
|
|
31
|
+
consecutive: number;
|
|
32
|
+
max: number;
|
|
33
|
+
};
|
|
34
|
+
export interface CadenceDecision {
|
|
35
|
+
shouldEscalate: boolean;
|
|
36
|
+
triggers: CadenceTrigger[];
|
|
37
|
+
}
|
|
38
|
+
export declare function evaluateFullAutoCadence(state: FullAutoRunState, config: PluginConfig, now?: number): CadenceDecision;
|
|
39
|
+
/**
|
|
40
|
+
* Convenience: increment the relevant counter and evaluate cadence in one
|
|
41
|
+
* call. Returns undefined when there is no active Full-Auto run.
|
|
42
|
+
*/
|
|
43
|
+
export declare function tickAndEvaluate(directory: string, sessionID: string, counter: 'toolCalls' | 'architectTurns', config: PluginConfig): CadenceDecision | undefined;
|
|
44
|
+
/**
|
|
45
|
+
* Tick a counter, evaluate cadence, and — if a trigger fires — dispatch the
|
|
46
|
+
* critic oversight agent in a non-blocking way. The dispatch:
|
|
47
|
+
* - increments the durable oversight counter
|
|
48
|
+
* - writes a `full_auto_oversight` event/evidence record
|
|
49
|
+
* - mutates durable run state (pause / terminate) according to verdict
|
|
50
|
+
*
|
|
51
|
+
* The chat.message and tool.execute.after callers do not await the dispatch
|
|
52
|
+
* — they fire-and-forget. The next tool call by the agent will see the
|
|
53
|
+
* paused/terminated state and surface a structured error.
|
|
54
|
+
*
|
|
55
|
+
* Returns the CadenceDecision so callers can introspect for tests.
|
|
56
|
+
*/
|
|
57
|
+
export declare function tickAndMaybeDispatchCadence(directory: string, sessionID: string, counter: 'toolCalls' | 'architectTurns', config: PluginConfig, options?: {
|
|
58
|
+
activeAgent?: string;
|
|
59
|
+
dispatch?: typeof dispatchFullAutoOversight;
|
|
60
|
+
}): CadenceDecision | undefined;
|
|
61
|
+
export declare const _internals: {
|
|
62
|
+
clearInFlight: () => void;
|
|
63
|
+
inFlight: Set<string>;
|
|
64
|
+
};
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Full-Auto v2 prompt-injection scanner for tool output.
|
|
3
|
+
*
|
|
4
|
+
* The probe inspects the textual content returned by a tool (web_search,
|
|
5
|
+
* webfetch, fetch, doc_extract, search, evidence dumps, etc.) and detects
|
|
6
|
+
* the most common prompt-injection / exfiltration shapes. It is intentionally
|
|
7
|
+
* pattern-based and conservative: false positives produce a warning but do
|
|
8
|
+
* not block work by themselves; an injection warning combined with a
|
|
9
|
+
* subsequent risky action escalates to the critic.
|
|
10
|
+
*/
|
|
11
|
+
export type FullAutoInputWarningCategory = 'instruction_override' | 'system_role_override' | 'credential_request' | 'exfiltration_request' | 'guardrail_disable_request' | 'curl_pipe_shell' | 'untrusted_run_command';
|
|
12
|
+
export interface FullAutoInputWarning {
|
|
13
|
+
category: FullAutoInputWarningCategory;
|
|
14
|
+
matched: string;
|
|
15
|
+
excerpt: string;
|
|
16
|
+
}
|
|
17
|
+
export interface FullAutoInputProbeResult {
|
|
18
|
+
hasWarning: boolean;
|
|
19
|
+
warnings: FullAutoInputWarning[];
|
|
20
|
+
}
|
|
21
|
+
export declare function probeFullAutoInput(text: string): FullAutoInputProbeResult;
|
|
22
|
+
export declare function shouldEscalateAfterWarning(toolName: string, commandOrUrl: string | undefined): boolean;
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
export interface FullAutoCriticResult {
|
|
2
|
+
verdict: string;
|
|
3
|
+
reasoning: string;
|
|
4
|
+
evidenceChecked: string[];
|
|
5
|
+
antiPatternsDetected: string[];
|
|
6
|
+
escalationNeeded: boolean;
|
|
7
|
+
rawResponse: string;
|
|
8
|
+
}
|
|
9
|
+
export type FullAutoTriggerSource = 'text_pattern' | 'tool_action' | 'cadence' | 'subagent_return' | 'phase_boundary' | 'task_completion' | 'risk';
|
|
10
|
+
export interface FullAutoOversightEvent {
|
|
11
|
+
type: 'full_auto_oversight';
|
|
12
|
+
timestamp: string;
|
|
13
|
+
session_id: string;
|
|
14
|
+
plan_id?: string;
|
|
15
|
+
phase?: number;
|
|
16
|
+
task_id?: string;
|
|
17
|
+
trigger_source: FullAutoTriggerSource;
|
|
18
|
+
trigger_reason: string;
|
|
19
|
+
critic_agent: string;
|
|
20
|
+
critic_model: string;
|
|
21
|
+
architect_model?: string;
|
|
22
|
+
verdict: string;
|
|
23
|
+
reasoning: string;
|
|
24
|
+
evidence_checked: string[];
|
|
25
|
+
anti_patterns_detected: string[];
|
|
26
|
+
escalation_needed: boolean;
|
|
27
|
+
decision: string;
|
|
28
|
+
full_auto_status_before?: string;
|
|
29
|
+
full_auto_status_after?: string;
|
|
30
|
+
oversight_sequence: number;
|
|
31
|
+
}
|
|
32
|
+
export interface DispatchFullAutoOversightInput {
|
|
33
|
+
directory: string;
|
|
34
|
+
sessionID: string;
|
|
35
|
+
trigger: string;
|
|
36
|
+
triggerSource: FullAutoTriggerSource;
|
|
37
|
+
phase?: number;
|
|
38
|
+
taskID?: string;
|
|
39
|
+
planID?: string;
|
|
40
|
+
architectOutput?: string;
|
|
41
|
+
actionContext?: Record<string, unknown>;
|
|
42
|
+
criticModel: string;
|
|
43
|
+
oversightAgentName: string;
|
|
44
|
+
architectModel?: string;
|
|
45
|
+
/**
|
|
46
|
+
* Optional Full-Auto config slice. Used to honor `fail_closed` semantics
|
|
47
|
+
* when oversight event/evidence persistence fails (TASK 6). When
|
|
48
|
+
* omitted, the dispatcher defaults to `fail_closed = true`.
|
|
49
|
+
*/
|
|
50
|
+
fullAutoConfig?: {
|
|
51
|
+
fail_closed?: boolean;
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
export declare function parseFullAutoCriticResponse(rawResponse: string): FullAutoCriticResult;
|
|
55
|
+
/**
|
|
56
|
+
* Append a Full-Auto oversight event to `.swarm/events.jsonl`.
|
|
57
|
+
*
|
|
58
|
+
* TASK 6: persistence failures MUST propagate. When fail_closed is the
|
|
59
|
+
* active policy (the default), an oversight verdict that cannot be
|
|
60
|
+
* durably audited is not a real verdict — the dispatcher converts the
|
|
61
|
+
* thrown error into a BLOCKED/pause outcome.
|
|
62
|
+
*
|
|
63
|
+
* The lock acquisition is best-effort (some platforms / test sandboxes
|
|
64
|
+
* cannot acquire the cross-process lock); the actual append is the
|
|
65
|
+
* mandatory step and any failure throws.
|
|
66
|
+
*/
|
|
67
|
+
export declare function writeFullAutoOversightEvent(directory: string, event: FullAutoOversightEvent): Promise<void>;
|
|
68
|
+
/**
|
|
69
|
+
* Persist Full-Auto oversight evidence to `.swarm/evidence/{phase}/full-auto-{seq}.json`.
|
|
70
|
+
*
|
|
71
|
+
* TASK 6: persistence failures MUST propagate. For phase_boundary
|
|
72
|
+
* triggers the evidence write is MANDATORY because phase_complete will
|
|
73
|
+
* later block on the absence of an APPROVED record. The dispatcher
|
|
74
|
+
* converts a thrown error into a BLOCKED/pause outcome under
|
|
75
|
+
* fail_closed = true.
|
|
76
|
+
*
|
|
77
|
+
* Returns `undefined` only when `phase` is undefined (no evidence to
|
|
78
|
+
* write because the trigger isn't phase-scoped). All other failures
|
|
79
|
+
* throw.
|
|
80
|
+
*/
|
|
81
|
+
export declare function writeFullAutoOversightEvidence(directory: string, phase: number | undefined, event: FullAutoOversightEvent): Promise<string | undefined>;
|
|
82
|
+
export interface FullAutoOversightOutcome extends FullAutoCriticResult {
|
|
83
|
+
decision: 'allow' | 'deny' | 'pause' | 'escalate_human' | 'pending';
|
|
84
|
+
event: FullAutoOversightEvent;
|
|
85
|
+
evidencePath?: string;
|
|
86
|
+
}
|
|
87
|
+
export declare function dispatchFullAutoOversight(input: DispatchFullAutoOversightInput): Promise<FullAutoOversightOutcome>;
|
|
88
|
+
/**
|
|
89
|
+
* Test-only DI seam.
|
|
90
|
+
*/
|
|
91
|
+
export declare const _internals: {
|
|
92
|
+
resetSequence: () => void;
|
|
93
|
+
};
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { PluginConfig } from '../config';
|
|
2
|
+
export interface PhaseApprovalDecision {
|
|
3
|
+
ok: boolean;
|
|
4
|
+
reason?: string;
|
|
5
|
+
evidence?: Record<string, unknown>;
|
|
6
|
+
}
|
|
7
|
+
export declare function verifyFullAutoPhaseApproval(directory: string, sessionID: string | undefined, phase: number, config: PluginConfig): PhaseApprovalDecision;
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
export type FullAutoActionTier = 'safe' | 'local' | 'medium' | 'high';
|
|
2
|
+
export type FullAutoDecision = {
|
|
3
|
+
action: 'allow';
|
|
4
|
+
reason: string;
|
|
5
|
+
tier: 'safe' | 'local';
|
|
6
|
+
} | {
|
|
7
|
+
action: 'deny';
|
|
8
|
+
reason: string;
|
|
9
|
+
code: string;
|
|
10
|
+
recoverable: boolean;
|
|
11
|
+
} | {
|
|
12
|
+
action: 'escalate_critic';
|
|
13
|
+
reason: string;
|
|
14
|
+
risk: 'medium' | 'high';
|
|
15
|
+
context: Record<string, unknown>;
|
|
16
|
+
} | {
|
|
17
|
+
action: 'escalate_human';
|
|
18
|
+
reason: string;
|
|
19
|
+
code: string;
|
|
20
|
+
} | {
|
|
21
|
+
action: 'pause';
|
|
22
|
+
reason: string;
|
|
23
|
+
code: string;
|
|
24
|
+
};
|
|
25
|
+
export interface FullAutoPolicyConfig {
|
|
26
|
+
enabled?: boolean;
|
|
27
|
+
mode?: 'assisted' | 'supervised' | 'strict';
|
|
28
|
+
permission_policy?: {
|
|
29
|
+
enabled?: boolean;
|
|
30
|
+
trusted_roots?: string[];
|
|
31
|
+
trusted_domains?: string[];
|
|
32
|
+
protected_paths?: string[];
|
|
33
|
+
allow_defaults?: boolean;
|
|
34
|
+
};
|
|
35
|
+
oversight?: {
|
|
36
|
+
on_high_risk_action?: boolean;
|
|
37
|
+
on_task_completion?: boolean;
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
export interface FullAutoClassifierInput {
|
|
41
|
+
sessionID: string;
|
|
42
|
+
agentName?: string;
|
|
43
|
+
normalizedAgentName?: string;
|
|
44
|
+
toolName: string;
|
|
45
|
+
args: Record<string, unknown> | undefined;
|
|
46
|
+
directory: string;
|
|
47
|
+
workingDirectory?: string;
|
|
48
|
+
declaredScope?: string[] | null;
|
|
49
|
+
currentTaskID?: string | null;
|
|
50
|
+
currentPhase?: number;
|
|
51
|
+
planSummary?: string;
|
|
52
|
+
changedFiles?: string[];
|
|
53
|
+
fullAutoConfig: FullAutoPolicyConfig | undefined;
|
|
54
|
+
}
|
|
55
|
+
export declare function isReadOnlyTool(toolName: string): boolean;
|
|
56
|
+
export declare function isWriteLikeTool(toolName: string): boolean;
|
|
57
|
+
export declare function isSubagentDelegation(toolName: string, args: Record<string, unknown> | undefined): boolean;
|
|
58
|
+
export declare function isProtectedPath(filePath: string, config: FullAutoPolicyConfig | undefined): boolean;
|
|
59
|
+
export declare function classifyPathRisk(filePath: string, context: {
|
|
60
|
+
directory: string;
|
|
61
|
+
declaredScope?: string[] | null;
|
|
62
|
+
}): {
|
|
63
|
+
withinProjectRoot: boolean;
|
|
64
|
+
withinDeclaredScope: boolean | null;
|
|
65
|
+
protected: boolean;
|
|
66
|
+
highRiskBuild: boolean;
|
|
67
|
+
};
|
|
68
|
+
export declare function classifyCommandRisk(command: string, _cwd: string, _context: {
|
|
69
|
+
directory: string;
|
|
70
|
+
}): {
|
|
71
|
+
decision: 'allow' | 'deny' | 'escalate_critic';
|
|
72
|
+
reason: string;
|
|
73
|
+
};
|
|
74
|
+
export declare function classifyFullAutoToolAction(input: FullAutoClassifierInput): FullAutoDecision;
|
|
75
|
+
export interface StructuredDenial {
|
|
76
|
+
full_auto_denial: true;
|
|
77
|
+
tool?: string;
|
|
78
|
+
code: string;
|
|
79
|
+
reason: string;
|
|
80
|
+
recoverable: boolean;
|
|
81
|
+
guidance: string;
|
|
82
|
+
}
|
|
83
|
+
export declare function buildStructuredDenial(decision: Extract<FullAutoDecision, {
|
|
84
|
+
action: 'deny';
|
|
85
|
+
}>, tool?: string): StructuredDenial;
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
export type FullAutoStatus = 'idle' | 'running' | 'paused' | 'terminated';
|
|
2
|
+
export interface FullAutoDenialRecord {
|
|
3
|
+
timestamp: string;
|
|
4
|
+
tool?: string;
|
|
5
|
+
code?: string;
|
|
6
|
+
reason: string;
|
|
7
|
+
}
|
|
8
|
+
export interface FullAutoCounters {
|
|
9
|
+
architectTurns: number;
|
|
10
|
+
toolCalls: number;
|
|
11
|
+
coderDelegations: number;
|
|
12
|
+
reviewerRejections: number;
|
|
13
|
+
testFailures: number;
|
|
14
|
+
oversightChecks: number;
|
|
15
|
+
consecutiveNoProgressTurns: number;
|
|
16
|
+
}
|
|
17
|
+
export interface FullAutoRunState {
|
|
18
|
+
status: FullAutoStatus;
|
|
19
|
+
sessionID: string;
|
|
20
|
+
mode: 'assisted' | 'supervised' | 'strict';
|
|
21
|
+
planID?: string;
|
|
22
|
+
currentPhase?: number;
|
|
23
|
+
currentTaskID?: string;
|
|
24
|
+
startedAt: string;
|
|
25
|
+
updatedAt: string;
|
|
26
|
+
lastOversightAt?: string;
|
|
27
|
+
lastOversightReason?: string;
|
|
28
|
+
lastOversightVerdict?: string;
|
|
29
|
+
denialCounters: {
|
|
30
|
+
consecutive: number;
|
|
31
|
+
total: number;
|
|
32
|
+
};
|
|
33
|
+
denialHistory: FullAutoDenialRecord[];
|
|
34
|
+
counters: FullAutoCounters;
|
|
35
|
+
pauseReason?: string;
|
|
36
|
+
terminateReason?: string;
|
|
37
|
+
}
|
|
38
|
+
export interface FullAutoPersistedState {
|
|
39
|
+
version: 2;
|
|
40
|
+
updatedAt: string;
|
|
41
|
+
/**
|
|
42
|
+
* Monotonic counter for `full_auto_oversight` evidence-file sequencing.
|
|
43
|
+
* Persisted so the per-phase filename `full-auto-{seq}.json` does not
|
|
44
|
+
* collide after a process restart. (C4 fix.)
|
|
45
|
+
*/
|
|
46
|
+
oversightSequence?: number;
|
|
47
|
+
sessions: Record<string, FullAutoRunState>;
|
|
48
|
+
}
|
|
49
|
+
export interface FullAutoConfigShape {
|
|
50
|
+
enabled?: boolean;
|
|
51
|
+
mode?: 'assisted' | 'supervised' | 'strict';
|
|
52
|
+
denials?: {
|
|
53
|
+
max_consecutive?: number;
|
|
54
|
+
max_total?: number;
|
|
55
|
+
on_limit?: 'pause' | 'terminate';
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
export declare class FullAutoStateUnreadableError extends Error {
|
|
59
|
+
constructor(reason: string);
|
|
60
|
+
}
|
|
61
|
+
export declare function isFullAutoStateUnreadable(): {
|
|
62
|
+
unreadable: boolean;
|
|
63
|
+
reason: string;
|
|
64
|
+
};
|
|
65
|
+
declare function readPersisted(directory: string): FullAutoPersistedState;
|
|
66
|
+
/**
|
|
67
|
+
* Atomically persist Full-Auto durable state.
|
|
68
|
+
*
|
|
69
|
+
* TASK 3 fix: persistence failures MUST propagate. The previous
|
|
70
|
+
* implementation caught and logged write errors, which let
|
|
71
|
+
* `startFullAutoRun` (and the `/swarm full-auto on` command) silently
|
|
72
|
+
* report success even when nothing was written. Callers relied on the
|
|
73
|
+
* durable record to fail-closed; that contract is now enforced.
|
|
74
|
+
*
|
|
75
|
+
* Behavior:
|
|
76
|
+
* - Writes via `tmp -> fsync -> rename`, so a crash mid-write cannot
|
|
77
|
+
* truncate the canonical file.
|
|
78
|
+
* - Keeps `.bak` of the prior canonical file as a recovery hint.
|
|
79
|
+
* - Reads the file back after the rename and confirms the JSON
|
|
80
|
+
* round-trips. Any failure throws.
|
|
81
|
+
*/
|
|
82
|
+
declare function writePersisted(directory: string, persisted: FullAutoPersistedState): void;
|
|
83
|
+
export declare function loadFullAutoRunState(directory: string, sessionID: string): FullAutoRunState | undefined;
|
|
84
|
+
export declare function saveFullAutoRunState(directory: string, state: FullAutoRunState): void;
|
|
85
|
+
export declare function startFullAutoRun(directory: string, sessionID: string, config: FullAutoConfigShape | undefined, options?: {
|
|
86
|
+
planID?: string;
|
|
87
|
+
phase?: number;
|
|
88
|
+
taskID?: string;
|
|
89
|
+
}): FullAutoRunState;
|
|
90
|
+
export declare function pauseFullAutoRun(directory: string, sessionID: string, reason: string): FullAutoRunState | undefined;
|
|
91
|
+
export declare function terminateFullAutoRun(directory: string, sessionID: string, reason: string): FullAutoRunState | undefined;
|
|
92
|
+
export declare function isFullAutoRunActive(directory: string, sessionID: string): boolean;
|
|
93
|
+
export type FullAutoCounterKey = keyof FullAutoCounters;
|
|
94
|
+
export declare function incrementFullAutoCounter(directory: string, sessionID: string, counter: FullAutoCounterKey, delta?: number): FullAutoRunState | undefined;
|
|
95
|
+
export declare function recordFullAutoDenial(directory: string, sessionID: string, denial: {
|
|
96
|
+
tool?: string;
|
|
97
|
+
code?: string;
|
|
98
|
+
reason: string;
|
|
99
|
+
}): FullAutoRunState | undefined;
|
|
100
|
+
export declare function resetFullAutoDenials(directory: string, sessionID: string): FullAutoRunState | undefined;
|
|
101
|
+
/**
|
|
102
|
+
* Atomically increment and return the durable oversight-evidence sequence
|
|
103
|
+
* counter. Used by `writeFullAutoOversightEvidence` to produce stable,
|
|
104
|
+
* non-colliding evidence filenames across process restarts. (C4 fix.)
|
|
105
|
+
*/
|
|
106
|
+
export declare function nextFullAutoOversightSequence(directory: string): number;
|
|
107
|
+
export declare function recordFullAutoOversight(directory: string, sessionID: string, verdict: string, reason: string): FullAutoRunState | undefined;
|
|
108
|
+
export interface DenialLimitDecision {
|
|
109
|
+
pause: boolean;
|
|
110
|
+
reason?: string;
|
|
111
|
+
mode?: 'pause' | 'terminate';
|
|
112
|
+
}
|
|
113
|
+
export declare function shouldPauseForDenials(state: FullAutoRunState, config: FullAutoConfigShape | undefined): DenialLimitDecision;
|
|
114
|
+
/**
|
|
115
|
+
* Test-only DI seam — same rationale as `src/state.ts:_internals`.
|
|
116
|
+
*/
|
|
117
|
+
export declare const _internals: {
|
|
118
|
+
readPersisted: typeof readPersisted;
|
|
119
|
+
writePersisted: typeof writePersisted;
|
|
120
|
+
};
|
|
121
|
+
export {};
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import type { PluginConfig } from '../config';
|
|
2
|
+
export interface FullAutoDelegationHookOptions {
|
|
3
|
+
config: PluginConfig;
|
|
4
|
+
directory: string;
|
|
5
|
+
}
|
|
6
|
+
interface ToolBeforeInput {
|
|
7
|
+
tool: string;
|
|
8
|
+
sessionID: string;
|
|
9
|
+
callID?: string;
|
|
10
|
+
}
|
|
11
|
+
interface ToolBeforeOutput {
|
|
12
|
+
args: unknown;
|
|
13
|
+
}
|
|
14
|
+
interface ToolAfterInput {
|
|
15
|
+
tool: string;
|
|
16
|
+
sessionID: string;
|
|
17
|
+
callID?: string;
|
|
18
|
+
args?: unknown;
|
|
19
|
+
}
|
|
20
|
+
interface ToolAfterOutput {
|
|
21
|
+
output?: unknown;
|
|
22
|
+
error?: unknown;
|
|
23
|
+
}
|
|
24
|
+
export declare function createFullAutoDelegationHook(options: FullAutoDelegationHookOptions): {
|
|
25
|
+
toolBefore: (input: ToolBeforeInput, output: ToolBeforeOutput) => Promise<void>;
|
|
26
|
+
toolAfter: (input: ToolAfterInput, output: ToolAfterOutput) => Promise<void>;
|
|
27
|
+
};
|
|
28
|
+
export {};
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import type { PluginConfig } from '../config';
|
|
2
|
+
export interface FullAutoInputProbeHookOptions {
|
|
3
|
+
config: PluginConfig;
|
|
4
|
+
directory: string;
|
|
5
|
+
}
|
|
6
|
+
interface ToolAfterInput {
|
|
7
|
+
tool: string;
|
|
8
|
+
sessionID: string;
|
|
9
|
+
callID?: string;
|
|
10
|
+
}
|
|
11
|
+
interface ToolAfterOutput {
|
|
12
|
+
output?: unknown;
|
|
13
|
+
error?: unknown;
|
|
14
|
+
}
|
|
15
|
+
export interface PendingInputWarning {
|
|
16
|
+
tool: string;
|
|
17
|
+
at: string;
|
|
18
|
+
categories: string[];
|
|
19
|
+
}
|
|
20
|
+
export declare const fullAutoInputWarningStash: Map<string, PendingInputWarning>;
|
|
21
|
+
export declare function setPendingInputWarning(sessionID: string, warning: PendingInputWarning): void;
|
|
22
|
+
export declare function consumePendingInputWarning(sessionID: string): PendingInputWarning | undefined;
|
|
23
|
+
export declare function peekPendingInputWarning(sessionID: string): PendingInputWarning | undefined;
|
|
24
|
+
export declare function createFullAutoInputProbeHook(options: FullAutoInputProbeHookOptions): {
|
|
25
|
+
toolAfter: (input: ToolAfterInput, output: ToolAfterOutput) => Promise<void>;
|
|
26
|
+
};
|
|
27
|
+
export {};
|
|
@@ -58,7 +58,7 @@ export declare function injectVerdictIntoMessages(messages: MessageWithParts[],
|
|
|
58
58
|
* This function encapsulates the critic invocation and event writing flow.
|
|
59
59
|
* The critic response is awaited before writing the event to events.jsonl.
|
|
60
60
|
*/
|
|
61
|
-
export declare function dispatchCriticAndWriteEvent(directory: string, architectOutput: string, criticContext: string, criticModel: string, escalationType: 'phase_completion' | 'question', interactionCount: number, deadlockCount: number, oversightAgentName: string): Promise<CriticDispatchResult>;
|
|
61
|
+
export declare function dispatchCriticAndWriteEvent(directory: string, architectOutput: string, criticContext: string, criticModel: string, escalationType: 'phase_completion' | 'question', interactionCount: number, deadlockCount: number, oversightAgentName: string, sessionID?: string): Promise<CriticDispatchResult>;
|
|
62
62
|
/**
|
|
63
63
|
* Creates the full-auto intercept hook factory.
|
|
64
64
|
*
|