opencode-swarm 7.139.2 → 7.139.4
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/.opencode/skills/phase-wrap/SKILL.md +2 -2
- package/README.md +2 -2
- package/dist/background/stage-b-gates.d.ts +5 -1
- package/dist/background/task-envelope.d.ts +4 -4
- package/dist/cli/{config-doctor-hrb61yqe.js → config-doctor-whxr386t.js} +6 -6
- package/dist/cli/{core-g2dfh9fq.js → core-aj5g7an6.js} +5 -5
- package/dist/cli/{curation-policy-4tp0mbcb.js → curation-policy-anym2y3v.js} +8 -8
- package/dist/cli/{curator-drift-vfh07mqy.js → curator-drift-49p3jnte.js} +7 -7
- package/dist/cli/{curator-vpcs1p1v.js → curator-e8cvb55d.js} +41 -41
- package/dist/cli/curator-llm-factory-h9xbpgmw.js +61 -0
- package/dist/cli/{dispatch-b1fge4xk.js → dispatch-2s23fbcs.js} +4 -4
- package/dist/cli/{evidence-summary-service-kzxr71yd.js → evidence-summary-service-g82bsjqa.js} +16 -16
- package/dist/cli/{gate-evidence-z2b1ymnw.js → gate-evidence-72cgrvs2.js} +6 -5
- package/dist/cli/guardrail-explain-0be7msvq.js +62 -0
- package/dist/cli/{guardrail-log-2ftew0p3.js → guardrail-log-9mm5443g.js} +9 -9
- package/dist/cli/{hive-promoter-mpf0cfkk.js → hive-promoter-nnzs5x1r.js} +41 -41
- package/dist/cli/{index-w71cq27a.js → index-0e95eck5.js} +5 -5
- package/dist/cli/{index-5zyk8qgv.js → index-0xkjhgrf.js} +5 -5
- package/dist/cli/{index-q7ezzgwq.js → index-1kyex7z2.js} +1 -1
- package/dist/cli/{index-668dpw5e.js → index-33skgk1a.js} +1 -1
- package/dist/cli/{index-vm4xw9z3.js → index-41hkt36g.js} +2 -2
- package/dist/cli/{index-y111zefa.js → index-4nt52yr9.js} +80 -31
- package/dist/cli/{index-3jcyn8g6.js → index-4wjk296r.js} +1 -1
- package/dist/cli/{index-3radty3f.js → index-5azdnaty.js} +2 -2
- package/dist/cli/{index-8p9pasnp.js → index-5s23pfsy.js} +8 -8
- package/dist/cli/{index-5w7ekpy3.js → index-5z2xps64.js} +2 -2
- package/dist/cli/{index-0wp67gqj.js → index-6nzmp937.js} +61 -111
- package/dist/cli/{index-gvhvz176.js → index-6r522srn.js} +2 -2
- package/dist/cli/{index-4xbyy6aw.js → index-6rxgb5r9.js} +10 -6
- package/dist/cli/{index-cyw81ngh.js → index-6vh6vrnk.js} +10 -10
- package/dist/cli/{index-a12906mj.js → index-6z0a940s.js} +8 -8
- package/dist/cli/{index-wsdnttf4.js → index-74hpm6sh.js} +1 -1
- package/dist/cli/{index-6w1re1qn.js → index-9cdj4020.js} +6 -6
- package/dist/cli/{index-y47dwge1.js → index-e1k9vpqn.js} +5 -5
- package/dist/cli/{index-y64jv2pe.js → index-ejbcpbzp.js} +7 -7
- package/dist/cli/{index-6c5f309q.js → index-gfmrw2f5.js} +2 -2
- package/dist/cli/{index-prmb5qfp.js → index-j77frjq8.js} +7 -7
- package/dist/cli/{index-ffpmqx30.js → index-jnfyxeap.js} +4 -4
- package/dist/cli/{index-e9tx99ds.js → index-k41dn8me.js} +3 -3
- package/dist/cli/{index-x9q4bbhd.js → index-k46me75h.js} +4 -4
- package/dist/cli/{index-s608d3hw.js → index-nrx08gcr.js} +6 -2
- package/dist/cli/{index-ktagrqxw.js → index-pg84msyc.js} +7 -7
- package/dist/cli/{index-a5eba0t8.js → index-rsrx77fg.js} +6 -6
- package/dist/cli/index-s0qc4gj6.js +298 -0
- package/dist/cli/{index-q11t5erh.js → index-s58vghgj.js} +7 -7
- package/dist/cli/{index-se8xc78k.js → index-sa15nfgg.js} +45 -45
- package/dist/cli/{index-wrt6m5ze.js → index-sd657fkp.js} +291 -75
- package/dist/cli/{index-yr6x707c.js → index-vfsqpcz6.js} +16 -16
- package/dist/cli/{index-a7nh382r.js → index-vyqd1hzm.js} +20593 -19882
- package/dist/cli/{index-8gftfvpp.js → index-xb1zq933.js} +1 -1
- package/dist/cli/{index-3eddtgxt.js → index-xmhhhjjw.js} +39 -4
- package/dist/cli/index.js +43 -43
- package/dist/cli/{knowledge-escalator-n9pmx4qr.js → knowledge-escalator-a6z30y9p.js} +10 -10
- package/dist/cli/{knowledge-events-raevm18w.js → knowledge-events-deq0ds8e.js} +7 -7
- package/dist/cli/{knowledge-link-3tq8w6gs.js → knowledge-link-bmbatt8s.js} +6 -6
- package/dist/cli/{knowledge-store-bcfqz8fr.js → knowledge-store-vdr19mnq.js} +8 -8
- package/dist/cli/{knowledge-validator-jxqj96cx.js → knowledge-validator-5hgacnrf.js} +11 -11
- package/dist/cli/{pending-delegations-tmyf18p4.js → pending-delegations-7ayryxbg.js} +8 -8
- package/dist/cli/{pr-subscriptions-hhx6yk24.js → pr-subscriptions-w5y08ebc.js} +8 -8
- package/dist/cli/{runner-w30gazew.js → runner-h7vmgkth.js} +7 -6
- package/dist/cli/{scan-cursor-ah5swtyh.js → scan-cursor-d6qcg9hr.js} +9 -9
- package/dist/cli/{schema-f7jgrtxj.js → schema-y1zekrag.js} +3 -3
- package/dist/cli/{scope-persistence-3f0d4fwv.js → scope-persistence-tj6qway9.js} +7 -7
- package/dist/cli/{skill-generator-hp7as46c.js → skill-generator-bw8xhzzn.js} +13 -13
- package/dist/cli/{task-envelope-qn0qtnh0.js → task-envelope-jp2fdsvn.js} +11 -8
- package/dist/cli/{telemetry-4tgrfhaz.js → telemetry-62cn5t24.js} +1 -1
- package/dist/cli/{workspace-snapshot-h5rzw37b.js → workspace-snapshot-w3tg4ne5.js} +2 -2
- package/dist/cli/{worktree-collision-ownership-vexb0b6r.js → worktree-collision-ownership-hs5c2qzp.js} +9 -9
- package/dist/commands/approve-plan-critic.d.ts +2 -2
- package/dist/commands/registry.d.ts +1 -1
- package/dist/config/agent-model.d.ts +35 -0
- package/dist/db/qa-gate-profile.d.ts +11 -3
- package/dist/evidence/manager.d.ts +5 -2
- package/dist/evidence/phase-participation.d.ts +44 -0
- package/dist/hooks/compaction-customizer.d.ts +30 -2
- package/dist/hooks/context-budget.d.ts +1 -1
- package/dist/hooks/delegation-gate.d.ts +3 -3
- package/dist/hooks/guardrails/index.d.ts +5 -1
- package/dist/hooks/guardrails/messages-transform.d.ts +2 -0
- package/dist/hooks/guardrails/pre-check-result.d.ts +20 -0
- package/dist/index.js +616 -609
- package/dist/prm/escalation.d.ts +34 -0
- package/dist/prm/index.d.ts +6 -2
- package/dist/prm/pattern-detector.d.ts +22 -1
- package/dist/prm/types.d.ts +12 -2
- package/dist/sast/semgrep.d.ts +15 -32
- package/dist/services/compaction-service.d.ts +3 -1
- package/dist/session/snapshot-writer.d.ts +1 -0
- package/dist/state.d.ts +119 -19
- package/dist/summaries/schema.d.ts +2 -2
- package/dist/tools/context-status.d.ts +4 -1
- package/dist/tools/convene-council.d.ts +1 -1
- package/dist/tools/lint.d.ts +48 -22
- package/dist/tools/pre-check-batch.d.ts +41 -13
- package/dist/tools/quality-budget.d.ts +3 -2
- package/dist/tools/resolve-working-directory.d.ts +4 -4
- package/dist/tools/sast-baseline.d.ts +1 -0
- package/dist/tools/sast-scan.d.ts +4 -1
- package/dist/tools/secretscan.d.ts +2 -2
- package/dist/tools/set-qa-gates.d.ts +5 -4
- package/dist/tools/submit-phase-council-verdicts.d.ts +1 -1
- package/dist/tools/write-final-council-evidence.d.ts +1 -1
- package/dist/utils/bun-compat.d.ts +20 -0
- package/dist/utils/external-tool-runner.d.ts +10 -0
- package/dist/utils/project-boundary.d.ts +34 -0
- package/package.json +1 -1
- package/dist/cli/curator-llm-factory-hvw13hmr.js +0 -61
- package/dist/cli/guardrail-explain-k62h3c92.js +0 -62
- package/dist/cli/index-5j6chvj8.js +0 -159
- package/dist/cli/{index-z6xqpmqg.js → index-ee3x66a5.js} +3 -3
package/dist/prm/escalation.d.ts
CHANGED
|
@@ -3,6 +3,30 @@
|
|
|
3
3
|
* Implements a 3-strike protocol for pattern detection escalation
|
|
4
4
|
*/
|
|
5
5
|
import type { CourseCorrection, EscalationState, PatternMatch } from './types';
|
|
6
|
+
/**
|
|
7
|
+
* Resolves the LADDER key for a match — the identity whose 1→2→3 strike count
|
|
8
|
+
* this detection belongs to (issue #2134 follow-up).
|
|
9
|
+
*
|
|
10
|
+
* The ladder used to be keyed by pattern TYPE alone, so unrelated occurrences
|
|
11
|
+
* accumulated into one count: a coder that read-then-re-read three different
|
|
12
|
+
* files produced three `repetition_loop` strikes on three different targets and
|
|
13
|
+
* hit the hard stop, even though it had not repeated itself even twice on any
|
|
14
|
+
* one of them. "Three strikes" has to mean "the same behaviour three times".
|
|
15
|
+
*
|
|
16
|
+
* A pattern reporting exactly ONE affected target gets a per-target ladder —
|
|
17
|
+
* `repetition_loop`, `ping_pong` and `stuck_on_test` all name the single file or
|
|
18
|
+
* target they are about, so that target IS the behaviour's identity.
|
|
19
|
+
*
|
|
20
|
+
* A pattern reporting a SET of targets keeps the per-pattern-type ladder.
|
|
21
|
+
* `context_thrash` and `expansion_drift` describe one ongoing episode over a
|
|
22
|
+
* growing collection of targets; keying those by target would mint a fresh
|
|
23
|
+
* ladder on every tool call and they could never escalate at all — the exact
|
|
24
|
+
* fail-open shape that the per-detector containment review caught the first time.
|
|
25
|
+
*
|
|
26
|
+
* Agents are deliberately not in the key. Escalation is about the work, not who
|
|
27
|
+
* did it, and `ping_pong` names two agents by construction.
|
|
28
|
+
*/
|
|
29
|
+
export declare function resolveLadderKey(match: PatternMatch): string;
|
|
6
30
|
/**
|
|
7
31
|
* Creates a default EscalationState with all counters reset and flags cleared.
|
|
8
32
|
* Exported for testing purposes.
|
|
@@ -48,6 +72,16 @@ export declare class EscalationTracker {
|
|
|
48
72
|
* @returns The current EscalationState copy
|
|
49
73
|
*/
|
|
50
74
|
getState(): EscalationState;
|
|
75
|
+
/**
|
|
76
|
+
* Returns a defensive copy of just the ladder counts (issue #2134 follow-up).
|
|
77
|
+
*
|
|
78
|
+
* `src/prm/index.ts` mirrors these onto the session after every strike so a
|
|
79
|
+
* tracker rebuilt mid-session restores the same keyspace it counts in. Using
|
|
80
|
+
* `getState()` there deep-cloned the whole state — including `stepRange`,
|
|
81
|
+
* `affectedAgents` and `affectedTargets` of the last match — on the
|
|
82
|
+
* per-tool-call hot path, for one field.
|
|
83
|
+
*/
|
|
84
|
+
getLadderCounts(): Map<string, number>;
|
|
51
85
|
/**
|
|
52
86
|
* Resets all escalation counts and flags to their default values.
|
|
53
87
|
* Clears pattern counts and all flags.
|
package/dist/prm/index.d.ts
CHANGED
|
@@ -13,8 +13,8 @@
|
|
|
13
13
|
* while PRM provides deeper multi-pattern detection and escalation.
|
|
14
14
|
*/
|
|
15
15
|
export { formatCourseCorrectionForInjection, generateCourseCorrection, } from './course-correction';
|
|
16
|
-
export { createDefaultEscalationState, EscalationTracker } from './escalation';
|
|
17
|
-
export { detectContextThrash, detectExpansionDrift, detectPatterns, detectPingPong, detectRepetitionLoop, detectStuckOnTest, } from './pattern-detector';
|
|
16
|
+
export { createDefaultEscalationState, EscalationTracker, resolveLadderKey, } from './escalation';
|
|
17
|
+
export { detectContextThrash, detectExpansionDrift, detectPatterns, detectPingPong, detectRepetitionLoop, detectStuckOnTest, resolvePatternThreshold, } from './pattern-detector';
|
|
18
18
|
export type { CourseCorrection, EscalationState, PatternDetectionResult, PatternMatch, PatternSeverity, PatternType, PrmConfig, TaxonomyCategory, TrajectoryEntry, } from './types';
|
|
19
19
|
import type { LearningConfig } from '../config/schema.js';
|
|
20
20
|
import { appendInsightCandidates } from '../hooks/micro-reflector.js';
|
|
@@ -78,6 +78,10 @@ interface ResettablePrmSessionState {
|
|
|
78
78
|
prmHardStopInjectPending?: boolean;
|
|
79
79
|
prmTrajectoryStep?: number;
|
|
80
80
|
prmInjectedAdvisoryKeys?: Set<string>;
|
|
81
|
+
/** Issue #2134 — episode ledger; reset with the trajectory cursor it indexes. */
|
|
82
|
+
prmStruckEpisodes?: Map<string, number>;
|
|
83
|
+
/** Issue #2134 follow-up — ladder counts; reset with the ledger. */
|
|
84
|
+
prmLadderCounts?: Map<string, number>;
|
|
81
85
|
replayArtifactPath?: string | null;
|
|
82
86
|
}
|
|
83
87
|
export declare function resetPrmSessionState(session: ResettablePrmSessionState, sessionId?: string): void;
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* PRM Pattern Detector
|
|
3
3
|
* Rule-based pattern detection for trajectory analysis
|
|
4
4
|
*/
|
|
5
|
-
import type { PatternDetectionResult, PatternMatch, PrmConfig, TrajectoryEntry } from './types';
|
|
5
|
+
import type { PatternDetectionResult, PatternMatch, PatternType, PrmConfig, TrajectoryEntry } from './types';
|
|
6
6
|
/**
|
|
7
7
|
* Sanitize a string to prevent prompt injection attacks.
|
|
8
8
|
* Removes newlines, carriage returns, backticks, and common injection patterns.
|
|
@@ -12,6 +12,27 @@ import type { PatternDetectionResult, PatternMatch, PrmConfig, TrajectoryEntry }
|
|
|
12
12
|
* @returns Sanitized string safe for embedding in prompts
|
|
13
13
|
*/
|
|
14
14
|
export declare function sanitizeString(input: string): string;
|
|
15
|
+
/**
|
|
16
|
+
* Resolves the configured occurrence threshold for a pattern type, falling back
|
|
17
|
+
* to the built-in default.
|
|
18
|
+
*
|
|
19
|
+
* Exported for the escalation ladder (issue #2134): the ladder re-strikes a
|
|
20
|
+
* still-running episode once it has grown by another threshold's worth of
|
|
21
|
+
* occurrences, so it must resolve the threshold exactly the way the detectors do
|
|
22
|
+
* or the two layers disagree about what "another occurrence" means.
|
|
23
|
+
*
|
|
24
|
+
* The threshold is NOT in a single unit across detectors, and the ladder does not
|
|
25
|
+
* pretend otherwise — it is repeats for `repetition_loop`, run length for
|
|
26
|
+
* `context_thrash`, cycle count for `stuck_on_test`, alternating-entry count for
|
|
27
|
+
* `ping_pong` (whose `occurrenceCount` is ROUND TRIPS, i.e. half that unit, so it
|
|
28
|
+
* re-strikes at twice the nominal spacing), and a growth RATIO for
|
|
29
|
+
* `expansion_drift` (whose `occurrenceCount` is a float near 1.5–3.0, so the
|
|
30
|
+
* growth ground is effectively inert for it and its re-strikes come from the
|
|
31
|
+
* new-episode ground instead — its comparison window steps by `windowSize`, so
|
|
32
|
+
* its episode start step genuinely advances). Every one of the five is verified
|
|
33
|
+
* to still reach a hard stop; see `src/prm/__tests__/issue-2134-episode-gate.test.ts`.
|
|
34
|
+
*/
|
|
35
|
+
export declare function resolvePatternThreshold(config: PrmConfig, pattern: PatternType): number;
|
|
15
36
|
/**
|
|
16
37
|
* Detect repetition_loop pattern
|
|
17
38
|
* Same agent targets same file with same action within N steps
|
package/dist/prm/types.d.ts
CHANGED
|
@@ -107,8 +107,18 @@ export interface PrmConfig {
|
|
|
107
107
|
* Per-session escalation tracking state
|
|
108
108
|
*/
|
|
109
109
|
export interface EscalationState {
|
|
110
|
-
/**
|
|
111
|
-
|
|
110
|
+
/**
|
|
111
|
+
* Ladder identity to strike-count mapping.
|
|
112
|
+
*
|
|
113
|
+
* Keyed by `resolveLadderKey(match)` (issue #2134 follow-up), NOT by pattern
|
|
114
|
+
* type: `pattern|target` for a single-target pattern, bare `pattern` for one
|
|
115
|
+
* reporting a growing target set. Keying the ladder by pattern type alone let
|
|
116
|
+
* unrelated occurrences on different files accumulate into a hard stop.
|
|
117
|
+
*
|
|
118
|
+
* Distinct from `AgentSessionState.prmPatternCounts`, which stays keyed by
|
|
119
|
+
* pattern type as the observable per-pattern tally.
|
|
120
|
+
*/
|
|
121
|
+
patternCounts: Map<string, number>;
|
|
112
122
|
/** Current escalation level (0=none, 1=guidance, 2=strong guidance, 3=hard stop) */
|
|
113
123
|
escalationLevel: number;
|
|
114
124
|
/** Last pattern detected (if any) */
|
package/dist/sast/semgrep.d.ts
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
* Semgrep Integration for Tier B SAST Enhancement
|
|
3
3
|
* Provides optional Semgrep detection and invocation for advanced static analysis
|
|
4
4
|
*/
|
|
5
|
+
import { resolveExecutableFromPath, runExternalTool } from '../utils/external-tool-runner';
|
|
5
6
|
import type { SastFinding } from './rules/index.js';
|
|
6
7
|
/**
|
|
7
8
|
* Semgrep CLI options
|
|
@@ -19,6 +20,8 @@ export interface SemgrepOptions {
|
|
|
19
20
|
lang?: string;
|
|
20
21
|
/** When true, use --config auto instead of local rulesDir (for profile-driven languages) */
|
|
21
22
|
useAutoConfig?: boolean;
|
|
23
|
+
/** Host/tool cancellation propagated to the shared subprocess runner. */
|
|
24
|
+
abortSignal?: AbortSignal;
|
|
22
25
|
}
|
|
23
26
|
/**
|
|
24
27
|
* Result from Semgrep execution
|
|
@@ -33,6 +36,8 @@ export interface SemgrepResult {
|
|
|
33
36
|
/** Engine label for the findings */
|
|
34
37
|
engine: 'tier_a' | 'tier_a+tier_b';
|
|
35
38
|
}
|
|
39
|
+
declare function resolveSemgrepBinary(): string | null;
|
|
40
|
+
declare function getAvailabilityProbeCwd(): string;
|
|
36
41
|
export declare const _internals: {
|
|
37
42
|
isSemgrepAvailable: typeof isSemgrepAvailable;
|
|
38
43
|
checkSemgrepAvailable: typeof checkSemgrepAvailable;
|
|
@@ -40,48 +45,26 @@ export declare const _internals: {
|
|
|
40
45
|
runSemgrep: typeof runSemgrep;
|
|
41
46
|
getRulesDirectory: typeof getRulesDirectory;
|
|
42
47
|
hasBundledRules: typeof hasBundledRules;
|
|
43
|
-
|
|
48
|
+
resolveExecutableFromPath: typeof resolveExecutableFromPath;
|
|
49
|
+
resolveSemgrepBinary: typeof resolveSemgrepBinary;
|
|
50
|
+
runExternalTool: typeof runExternalTool;
|
|
51
|
+
getAvailabilityProbeCwd: typeof getAvailabilityProbeCwd;
|
|
44
52
|
};
|
|
45
53
|
/**
|
|
46
|
-
*
|
|
47
|
-
*
|
|
48
|
-
*
|
|
54
|
+
* Synchronous compatibility surface.
|
|
55
|
+
* Returns the last confirmed async availability result when cached; otherwise
|
|
56
|
+
* falls back to a pure PATH-resolution heuristic without spawning.
|
|
49
57
|
*/
|
|
50
58
|
export declare function isSemgrepAvailable(): boolean;
|
|
51
59
|
/**
|
|
52
|
-
*
|
|
53
|
-
*
|
|
60
|
+
* Bounded async availability probe used by the live batch path.
|
|
61
|
+
* Caches only the result of the real shared-runner probe.
|
|
54
62
|
*/
|
|
55
|
-
export declare function checkSemgrepAvailable(): Promise<boolean>;
|
|
63
|
+
export declare function checkSemgrepAvailable(cwd?: string, abortSignal?: AbortSignal): Promise<boolean>;
|
|
56
64
|
/**
|
|
57
65
|
* Reset the Semgrep availability cache (useful for testing)
|
|
58
66
|
*/
|
|
59
67
|
export declare function resetSemgrepCache(): void;
|
|
60
|
-
/**
|
|
61
|
-
* Execute a command with timeout
|
|
62
|
-
* @param command - Command to execute
|
|
63
|
-
* @param args - Command arguments (safe array, no shell injection)
|
|
64
|
-
* @param options - Execution options including timeout
|
|
65
|
-
* @returns Promise resolving to command output
|
|
66
|
-
*/
|
|
67
|
-
declare function executeWithTimeout(command: string, args: string[], options: {
|
|
68
|
-
cwd?: string;
|
|
69
|
-
timeoutMs: number;
|
|
70
|
-
maxOutputBytes?: number;
|
|
71
|
-
/**
|
|
72
|
-
* Test-only hook invoked once with the spawned child's pid, immediately
|
|
73
|
-
* after `spawn()` returns. Lets tests assert the child is actually
|
|
74
|
-
* reaped (not just that a placeholder exit code was set) without
|
|
75
|
-
* mocking `node:child_process` (which would leak across test files —
|
|
76
|
-
* AGENTS.md invariant 7). No production caller passes this.
|
|
77
|
-
*/
|
|
78
|
-
onSpawn?: (pid: number | undefined) => void;
|
|
79
|
-
}): Promise<{
|
|
80
|
-
stdout: string;
|
|
81
|
-
stderr: string;
|
|
82
|
-
exitCode: number;
|
|
83
|
-
truncated: boolean;
|
|
84
|
-
}>;
|
|
85
68
|
/**
|
|
86
69
|
* Run Semgrep on specified files
|
|
87
70
|
* @param options - Semgrep options
|
|
@@ -7,11 +7,13 @@
|
|
|
7
7
|
* - Reflection (default 60%): re-summarise into tighter format
|
|
8
8
|
* - Emergency (default 80%): hard truncation to system + current task + last N turns
|
|
9
9
|
*
|
|
10
|
-
* Consumes
|
|
10
|
+
* Consumes the per-session budget pct recorded by system-enhancer.ts after
|
|
11
|
+
* each budget calc (`getSessionBudgetPct`).
|
|
11
12
|
* Never throws. Advisory system message injection via callback.
|
|
12
13
|
*/
|
|
13
14
|
import type { CompactionConfig } from '../config/schema';
|
|
14
15
|
export type { CompactionConfig };
|
|
16
|
+
export declare const MAX_TRACKED_COMPACTION_SESSIONS = 500;
|
|
15
17
|
export interface CompactionServiceHook {
|
|
16
18
|
toolAfter: (input: {
|
|
17
19
|
tool: string;
|
package/dist/state.d.ts
CHANGED
|
@@ -166,6 +166,7 @@ export interface AgentSessionState {
|
|
|
166
166
|
tool: string;
|
|
167
167
|
taskId: string;
|
|
168
168
|
timestamp: number;
|
|
169
|
+
code?: string;
|
|
169
170
|
} | null;
|
|
170
171
|
/** Task IDs for which partial gate warning has already been issued (prevents per-task spam) */
|
|
171
172
|
partialGateWarningsIssuedForTask: Set<string>;
|
|
@@ -413,6 +414,55 @@ export interface AgentSessionState {
|
|
|
413
414
|
* fields, and this one is additive.
|
|
414
415
|
*/
|
|
415
416
|
prmHardStopInjectPending?: boolean;
|
|
417
|
+
/**
|
|
418
|
+
* Issue #2134 — episode ledger for the escalation ladder.
|
|
419
|
+
*
|
|
420
|
+
* Maps an episode key (`patternType|startStep`) to the occurrence count that
|
|
421
|
+
* episode had when it last recorded a strike. A detector re-emits the SAME
|
|
422
|
+
* ongoing episode on every tool call with a growing `stepRange[1]` (a coder
|
|
423
|
+
* reading more files extends one `context_thrash` run), and the trajectory
|
|
424
|
+
* cursor cannot suppress that because the episode's end step always advances
|
|
425
|
+
* past it. Counting each re-emission as a fresh strike walked ONE ordinary
|
|
426
|
+
* episode from level 1 to level 3 in three tool calls and wedged healthy coder
|
|
427
|
+
* sessions behind a hard stop.
|
|
428
|
+
*
|
|
429
|
+
* A match strikes when its episode is new, or when that episode has gained
|
|
430
|
+
* another full threshold's worth of occurrences since it last struck. Both
|
|
431
|
+
* rungs are needed: three of the five detectors never advance an episode's
|
|
432
|
+
* start step while it runs, so without the growth rung they would strike
|
|
433
|
+
* exactly once and could never reach level 2 or 3. See the EPISODE GATE
|
|
434
|
+
* comment in `src/prm/index.ts` for the per-detector derivation.
|
|
435
|
+
*
|
|
436
|
+
* Optional for the same reason as `prmHardStopInjectPending`: ~25 existing
|
|
437
|
+
* test/session literals enumerate the required PRM fields, and this is additive.
|
|
438
|
+
*/
|
|
439
|
+
prmStruckEpisodes?: Map<string, number>;
|
|
440
|
+
/**
|
|
441
|
+
* Issue #2134 follow-up — mirror of the escalation tracker's LADDER counts,
|
|
442
|
+
* keyed by `resolveLadderKey(match)` (`pattern|target`, or bare `pattern` for
|
|
443
|
+
* a pattern reporting a growing target set).
|
|
444
|
+
*
|
|
445
|
+
* Deliberately separate from `prmPatternCounts`, which stays keyed by pattern
|
|
446
|
+
* type as the observable per-pattern tally that telemetry and tests read. The
|
|
447
|
+
* two are different keyspaces and must not be conflated: the tracker-rebuild
|
|
448
|
+
* path below used to seed itself from `prmPatternCounts`, which would now
|
|
449
|
+
* hand pattern-type keys to a ladder that counts by target and silently
|
|
450
|
+
* mis-restore every count.
|
|
451
|
+
*/
|
|
452
|
+
prmLadderCounts?: Map<string, number>;
|
|
453
|
+
/**
|
|
454
|
+
* Issue #2134 — dispatch identity of the delegation whose start already reset
|
|
455
|
+
* this session's PRM state. Holds the Task tool `callID`, which is unique per
|
|
456
|
+
* dispatch.
|
|
457
|
+
*
|
|
458
|
+
* The reset hook (`delegationGateHooks.taskMetadata`) is driven by
|
|
459
|
+
* `message.part.updated`, which fires repeatedly for the SAME Task part as the
|
|
460
|
+
* child runs. An unguarded reset there would clear the escalation ladder on
|
|
461
|
+
* every part update and disarm PRM permanently — a fail-open far worse than
|
|
462
|
+
* the wedge it is meant to prevent. Comparing against this field makes the
|
|
463
|
+
* reset exactly once per dispatch.
|
|
464
|
+
*/
|
|
465
|
+
prmDelegationCallId?: string;
|
|
416
466
|
/** Per-session escalation tracker instance (set lazily by PRM hook) */
|
|
417
467
|
prmEscalationTracker?: EscalationTracker;
|
|
418
468
|
/** Cross-turn set of already-injected PRM advisory dedupe keys
|
|
@@ -596,26 +646,44 @@ export declare const swarmState: {
|
|
|
596
646
|
* matching). Populated by `src/index.ts` after `createAgents`.
|
|
597
647
|
*/
|
|
598
648
|
generatedAgentNames: string[];
|
|
599
|
-
/** Last known context budget percentage (0-100), updated by system-enhancer */
|
|
600
|
-
lastBudgetPct: number;
|
|
601
649
|
/**
|
|
602
|
-
*
|
|
603
|
-
*
|
|
604
|
-
*
|
|
605
|
-
*
|
|
606
|
-
*
|
|
607
|
-
*
|
|
608
|
-
*
|
|
650
|
+
* Last known context budget per session — keyed by sessionID.
|
|
651
|
+
*
|
|
652
|
+
* `pct` is the budget percentage (0-100); `tokens` is the DENOMINATOR it was
|
|
653
|
+
* computed against. They are stored together because a percentage without
|
|
654
|
+
* its denominator cannot be turned back into a token estimate, and
|
|
655
|
+
* `/swarm status` renders both — reading them from different sources would
|
|
656
|
+
* show a token figure that does not match the percentage beside it.
|
|
657
|
+
*
|
|
658
|
+
* Keyed rather than global (AGENTS.md invariant 8). These were two bare
|
|
659
|
+
* module-level scalars, which was harmless only while the budget check threw
|
|
660
|
+
* on every call and left them pinned at 0. Now that the check runs, a bare
|
|
661
|
+
* global leaks across sessions: a busy session reporting 85% would trip the
|
|
662
|
+
* default-on compaction service's emergency tier — and the `>= 50%` CONTEXT
|
|
663
|
+
* PRESSURE advisory — inside an unrelated small session. compaction-service
|
|
664
|
+
* keys its *hysteresis* per session, so the wrong session's state machine
|
|
665
|
+
* would advance on another session's number.
|
|
666
|
+
*
|
|
667
|
+
* Write via `setSessionBudget`, read via `getSessionBudgetPct` /
|
|
668
|
+
* `getSessionBudgetTokens`; `/swarm status` uses `getDisplayBudget`.
|
|
609
669
|
*/
|
|
610
|
-
|
|
670
|
+
lastBudgetBySession: Map<string, {
|
|
671
|
+
pct: number;
|
|
672
|
+
tokens: number;
|
|
673
|
+
}>;
|
|
611
674
|
/**
|
|
612
|
-
* Live `model.limit.context` per session — keyed by sessionID
|
|
613
|
-
* the
|
|
675
|
+
* Live `model.limit.context` per session — keyed by sessionID and bound to
|
|
676
|
+
* the reporting model/provider identity. Recorded by the
|
|
677
|
+
* `experimental.chat.system.transform` hook (the only hook the host
|
|
614
678
|
* gives a `Model` to) and read by the `experimental.chat.messages.transform`
|
|
615
679
|
* consumers, which receive messages but no model object. Bounded via
|
|
616
680
|
* {@link setLiveContextWindow} (AGENTS.md invariant 8).
|
|
617
681
|
*/
|
|
618
|
-
liveContextWindows: Map<string,
|
|
682
|
+
liveContextWindows: Map<string, {
|
|
683
|
+
tokens?: number;
|
|
684
|
+
modelID?: string;
|
|
685
|
+
providerID?: string;
|
|
686
|
+
}>;
|
|
619
687
|
/** Per-session guardrail state — keyed by sessionID */
|
|
620
688
|
agentSessions: Map<string, AgentSessionState>;
|
|
621
689
|
/** In-flight rehydration promises — awaited by rehydrateState before clearing agentSessions */
|
|
@@ -1157,13 +1225,15 @@ export declare function getResolvedAutoProceed(session: AgentSessionState, planA
|
|
|
1157
1225
|
export declare function setSessionEnvironment(sessionId: string, profile: EnvironmentProfile): void;
|
|
1158
1226
|
export declare function getSessionEnvironment(sessionId: string): EnvironmentProfile | undefined;
|
|
1159
1227
|
export declare function ensureSessionEnvironment(sessionId: string): EnvironmentProfile;
|
|
1228
|
+
export declare const MAX_TRACKED_BUDGET_SESSIONS = 500;
|
|
1160
1229
|
export declare const MAX_TRACKED_CRITICAL_SHOWN = 500;
|
|
1161
1230
|
export declare const MAX_TRACKED_KNOWLEDGE_ACKS = 5000;
|
|
1162
1231
|
export declare const MAX_TRACKED_GATE_DENIALS = 500;
|
|
1163
1232
|
export declare const MAX_TRACKED_CONTEXT_WINDOWS = 500;
|
|
1164
1233
|
/**
|
|
1165
1234
|
* Record the live `model.limit.context` the host reported for `sessionID`,
|
|
1166
|
-
* FIFO-evicting the oldest
|
|
1235
|
+
* bound to the reporting model/provider identity and FIFO-evicting the oldest
|
|
1236
|
+
* entry past {@link MAX_TRACKED_CONTEXT_WINDOWS}.
|
|
1167
1237
|
*
|
|
1168
1238
|
* Only accepts a finite number ≥ 1 — the caller (`src/config/context-window.ts`
|
|
1169
1239
|
* `isUsableContextWindow`) applies the real plausibility floor, and storing a
|
|
@@ -1171,14 +1241,44 @@ export declare const MAX_TRACKED_CONTEXT_WINDOWS = 500;
|
|
|
1171
1241
|
* rejected value leaves any previously recorded window in place rather than
|
|
1172
1242
|
* clobbering it, so one malformed turn does not blank a good reading.
|
|
1173
1243
|
*/
|
|
1174
|
-
export declare function setLiveContextWindow(sessionID: string | undefined, tokens: unknown
|
|
1244
|
+
export declare function setLiveContextWindow(sessionID: string | undefined, tokens: unknown, identity?: {
|
|
1245
|
+
modelID?: string;
|
|
1246
|
+
providerID?: string;
|
|
1247
|
+
}): void;
|
|
1175
1248
|
/**
|
|
1176
1249
|
* Read the live context window recorded for `sessionID`, or `undefined` when
|
|
1177
|
-
* no `system.transform` has run for it yet
|
|
1178
|
-
*
|
|
1179
|
-
* resolution rungs rather than
|
|
1250
|
+
* no `system.transform` has run for it yet or the requested model/provider
|
|
1251
|
+
* identity does not exactly match the reporter. Callers must degrade to the
|
|
1252
|
+
* static resolution rungs rather than reuse a stale handoff denominator.
|
|
1180
1253
|
*/
|
|
1181
|
-
export declare function getLiveContextWindow(sessionID: string | undefined
|
|
1254
|
+
export declare function getLiveContextWindow(sessionID: string | undefined, identity?: {
|
|
1255
|
+
modelID?: string;
|
|
1256
|
+
providerID?: string;
|
|
1257
|
+
}): number | undefined;
|
|
1258
|
+
export declare function getLiveContextModelIdentity(sessionID: string | undefined): {
|
|
1259
|
+
modelID?: string;
|
|
1260
|
+
providerID?: string;
|
|
1261
|
+
} | undefined;
|
|
1262
|
+
/** Record this session's budget percentage and the denominator it was computed
|
|
1263
|
+
* against, FIFO-evicting the oldest entry if the cap is exceeded. The two are
|
|
1264
|
+
* written together so `/swarm status` can never pair a pct from one report
|
|
1265
|
+
* with a denominator from another. */
|
|
1266
|
+
export declare function setSessionBudget(sessionID: string, pct: number, tokens: number): void;
|
|
1267
|
+
/** This session's last budget percentage, or 0 if it has not been measured.
|
|
1268
|
+
* Consumers that ACT on a session (compaction, the context-pressure advisory)
|
|
1269
|
+
* MUST use this rather than any cross-session aggregate. */
|
|
1270
|
+
export declare function getSessionBudgetPct(sessionID: string | undefined): number;
|
|
1271
|
+
/** The denominator this session's percentage was computed against, or 0. */
|
|
1272
|
+
export declare function getSessionBudgetTokens(sessionID: string | undefined): number;
|
|
1273
|
+
/** The most-pressured session's budget snapshot, for process-wide DISPLAY only
|
|
1274
|
+
* (`/swarm status` has no single session in scope). Returns the pct and its
|
|
1275
|
+
* OWN denominator as a pair, so the two figures shown side by side always come
|
|
1276
|
+
* from the same report. Null when nothing has been measured yet. Never use
|
|
1277
|
+
* this to decide whether to act on a particular session. */
|
|
1278
|
+
export declare function getDisplayBudget(): {
|
|
1279
|
+
pct: number;
|
|
1280
|
+
tokens: number;
|
|
1281
|
+
} | null;
|
|
1182
1282
|
/** Set the critical shown ids for a session, FIFO-evicting the oldest entry
|
|
1183
1283
|
* if the cap is exceeded. Re-setting an existing key keeps insertion order
|
|
1184
1284
|
* fresh for that key (delete-then-set). */
|
|
@@ -22,8 +22,8 @@ export declare const MAX_LIST_ITEMS = 5;
|
|
|
22
22
|
/** Verdict vocabulary — mirrors the phase-council gate (APPROVE | CONCERNS | REJECT). */
|
|
23
23
|
export declare const SupervisorVerdictSchema: z.ZodEnum<{
|
|
24
24
|
APPROVE: "APPROVE";
|
|
25
|
-
CONCERNS: "CONCERNS";
|
|
26
25
|
REJECT: "REJECT";
|
|
26
|
+
CONCERNS: "CONCERNS";
|
|
27
27
|
}>;
|
|
28
28
|
export type SupervisorVerdict = z.infer<typeof SupervisorVerdictSchema>;
|
|
29
29
|
/** Count whitespace-delimited words in a string. */
|
|
@@ -130,8 +130,8 @@ export declare const ArchitectureSupervisorReportSchema: z.ZodObject<{
|
|
|
130
130
|
phase: z.ZodNumber;
|
|
131
131
|
verdict: z.ZodEnum<{
|
|
132
132
|
APPROVE: "APPROVE";
|
|
133
|
-
CONCERNS: "CONCERNS";
|
|
134
133
|
REJECT: "REJECT";
|
|
134
|
+
CONCERNS: "CONCERNS";
|
|
135
135
|
}>;
|
|
136
136
|
findings: z.ZodDefault<z.ZodArray<z.ZodObject<{
|
|
137
137
|
severity: z.ZodEnum<{
|
|
@@ -83,7 +83,10 @@ export declare const _internals: {
|
|
|
83
83
|
* by the system.transform hook; `undefined` when none has been seen yet
|
|
84
84
|
* @returns Context status with token usage, limit, and threshold state
|
|
85
85
|
*/
|
|
86
|
-
declare function computeContextHeadroom(messages: ContextMessage[], warnThreshold?: number, criticalThreshold?: number, modelLimitsConfig?: Record<string, number>, liveContextLimit?: unknown
|
|
86
|
+
declare function computeContextHeadroom(messages: ContextMessage[], warnThreshold?: number, criticalThreshold?: number, modelLimitsConfig?: Record<string, number>, liveContextLimit?: unknown, modelIdentity?: {
|
|
87
|
+
modelID?: string;
|
|
88
|
+
providerID?: string;
|
|
89
|
+
}): ContextStatusResult;
|
|
87
90
|
/**
|
|
88
91
|
* context_status tool — read-only context window headroom report.
|
|
89
92
|
*
|
package/dist/tools/lint.d.ts
CHANGED
|
@@ -1,8 +1,19 @@
|
|
|
1
|
+
import * as fs from 'node:fs';
|
|
1
2
|
import type { tool } from '@opencode-ai/plugin';
|
|
3
|
+
import { isCommandAvailable } from '../build/discovery';
|
|
4
|
+
import { type ExternalToolRunOptions, type ExternalToolRunResult } from '../utils/external-tool-runner';
|
|
2
5
|
export declare const MAX_OUTPUT_BYTES = 512000;
|
|
3
6
|
export declare const MAX_COMMAND_LENGTH = 500;
|
|
4
7
|
export declare const SUPPORTED_LINTERS: readonly ["biome", "eslint"];
|
|
5
8
|
export type SupportedLinter = (typeof SUPPORTED_LINTERS)[number];
|
|
9
|
+
type ResolvedLinterSource = 'local-native' | 'local-shim' | 'safe-package-bin' | 'path-native' | 'path-shim' | 'legacy-test-probe';
|
|
10
|
+
export interface ResolvedLinterCommand {
|
|
11
|
+
linter: SupportedLinter;
|
|
12
|
+
executable: string;
|
|
13
|
+
argsPrefix: string[];
|
|
14
|
+
displayPrefix: string[];
|
|
15
|
+
source: ResolvedLinterSource;
|
|
16
|
+
}
|
|
6
17
|
export type AdditionalLinter = 'ruff' | 'clippy' | 'golangci-lint' | 'checkstyle' | 'ktlint' | 'dotnet-format' | 'cppcheck' | 'swiftlint' | 'dart-analyze' | 'rubocop' | 'phpstan' | 'pint' | 'php-cs-fixer' | 'phpcs';
|
|
7
18
|
export interface LintSuccessResult {
|
|
8
19
|
success: true;
|
|
@@ -28,46 +39,61 @@ export { containsControlChars, containsPathTraversal, } from '../utils/path-secu
|
|
|
28
39
|
export declare function validateArgs(args: unknown): args is {
|
|
29
40
|
mode: 'fix' | 'check';
|
|
30
41
|
};
|
|
42
|
+
export declare function getBiomeBinPath(directory: string): string;
|
|
43
|
+
export declare function getEslintBinPath(directory: string): string;
|
|
31
44
|
export declare function getLinterCommand(linter: SupportedLinter, mode: 'fix' | 'check', projectDir: string): string[];
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
*/
|
|
36
|
-
export declare function getAdditionalLinterCommand(linter: AdditionalLinter, mode: 'fix' | 'check', cwd: string): string[];
|
|
45
|
+
export declare function resolveLinterBinPath(linter: SupportedLinter, projectDir: string): string;
|
|
46
|
+
export declare function resolveLinterCommand(linter: SupportedLinter, directory: string): Promise<ResolvedLinterCommand | null>;
|
|
47
|
+
export declare function detectResolvedLinter(directory?: string, abortSignal?: AbortSignal): Promise<ResolvedLinterCommand | null>;
|
|
37
48
|
/**
|
|
38
49
|
* Detect the first available additional (non-JS/TS) linter for the current project.
|
|
39
50
|
* Returns null when no additional linter is detected or its binary is unavailable.
|
|
40
51
|
*/
|
|
41
52
|
export declare function detectAdditionalLinter(cwd: string): 'ruff' | 'clippy' | 'golangci-lint' | 'checkstyle' | 'ktlint' | 'dotnet-format' | 'cppcheck' | 'swiftlint' | 'dart-analyze' | 'rubocop' | 'phpstan' | 'pint' | 'php-cs-fixer' | 'phpcs' | null;
|
|
42
|
-
/** Compute the local biome binary path for a given project directory. */
|
|
43
|
-
export declare function getBiomeBinPath(directory: string): string;
|
|
44
|
-
/**
|
|
45
|
-
* Resolve the binary path for a linter, using the same hierarchy as detectAvailableLinter:
|
|
46
|
-
* 1. Local node_modules/.bin
|
|
47
|
-
* 2. Ancestor node_modules/.bin (monorepo)
|
|
48
|
-
* 3. process.env.PATH scan
|
|
49
|
-
* 4. Local path as fallback (may not exist)
|
|
50
|
-
*/
|
|
51
|
-
export declare function resolveLinterBinPath(linter: SupportedLinter, projectDir: string): string;
|
|
52
|
-
/** Compute the local eslint binary path for a given project directory. */
|
|
53
|
-
export declare function getEslintBinPath(directory: string): string;
|
|
54
53
|
export declare function detectAvailableLinter(directory?: string): Promise<SupportedLinter | null>;
|
|
55
54
|
/** Internal implementation — accepts pre-computed binary paths for testability. */
|
|
56
|
-
export declare function _detectAvailableLinter(
|
|
57
|
-
|
|
55
|
+
export declare function _detectAvailableLinter(projectDir: string, biomeBin: string, eslintBin: string): Promise<SupportedLinter | null>;
|
|
56
|
+
declare function runResolvedLint(command: ResolvedLinterCommand, mode: 'fix' | 'check', directory: string, abortSignal?: AbortSignal): Promise<LintResult>;
|
|
57
|
+
/**
|
|
58
|
+
* Build the shell command for an additional (non-JS/TS) linter.
|
|
59
|
+
* cppcheck has no --fix mode; csharp and some others behave differently.
|
|
60
|
+
*/
|
|
61
|
+
export declare function getAdditionalLinterCommand(linter: AdditionalLinter, mode: 'fix' | 'check', cwd: string): string[] | null;
|
|
62
|
+
export declare function runLint(linter: SupportedLinter, mode: 'fix' | 'check', directory: string, abortSignal?: AbortSignal): Promise<LintResult>;
|
|
58
63
|
/**
|
|
59
64
|
* Run an additional (non-JS/TS) linter.
|
|
60
65
|
* Follows the same structure as runLint() but uses getAdditionalLinterCommand().
|
|
61
66
|
*/
|
|
62
|
-
export declare function runAdditionalLint(linter: AdditionalLinter, mode: 'fix' | 'check', cwd: string): Promise<LintResult>;
|
|
67
|
+
export declare function runAdditionalLint(linter: AdditionalLinter, mode: 'fix' | 'check', cwd: string, abortSignal?: AbortSignal): Promise<LintResult>;
|
|
63
68
|
export declare const lint: ReturnType<typeof tool>;
|
|
64
69
|
/**
|
|
65
70
|
* DI seam for testability. Contains all test-mocked exports.
|
|
66
71
|
* Internal calls should use _internals.fn() instead of fn() directly.
|
|
67
72
|
*/
|
|
68
73
|
export declare const _internals: {
|
|
69
|
-
|
|
70
|
-
|
|
74
|
+
MAX_PACKAGE_MANIFEST_BYTES: number;
|
|
75
|
+
MAX_PATH_SHIM_BYTES: number;
|
|
76
|
+
arch: () => string;
|
|
77
|
+
closeSync: typeof fs.closeSync;
|
|
78
|
+
comSpec: () => string | undefined;
|
|
71
79
|
detectAdditionalLinter: typeof detectAdditionalLinter;
|
|
80
|
+
detectAvailableLinter: typeof detectAvailableLinter;
|
|
81
|
+
detectResolvedLinter: typeof detectResolvedLinter;
|
|
82
|
+
execPath: () => string;
|
|
83
|
+
existsSync: typeof fs.existsSync;
|
|
84
|
+
fstatSync: typeof fs.fstatSync;
|
|
85
|
+
isCommandAvailable: typeof isCommandAvailable;
|
|
86
|
+
openSync: typeof fs.openSync;
|
|
87
|
+
pathEnv: () => string;
|
|
88
|
+
platform: () => NodeJS.Platform;
|
|
89
|
+
readFileSync: typeof fs.readFileSync;
|
|
90
|
+
readSync: typeof fs.readSync;
|
|
91
|
+
readdirSync: typeof fs.readdirSync;
|
|
92
|
+
realpathSync: typeof fs.realpathSync;
|
|
93
|
+
resolveLinterCommand: typeof resolveLinterCommand;
|
|
72
94
|
runAdditionalLint: typeof runAdditionalLint;
|
|
95
|
+
runExternalTool: (options: ExternalToolRunOptions) => Promise<ExternalToolRunResult>;
|
|
96
|
+
runLint: typeof runLint;
|
|
97
|
+
runResolvedLint: typeof runResolvedLint;
|
|
98
|
+
statSync: typeof fs.statSync;
|
|
73
99
|
};
|