opencode-swarm 7.62.0 → 7.63.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.
@@ -1,3 +1,17 @@
1
+ interface PlanPhase {
2
+ id: number;
3
+ name: string;
4
+ status: string;
5
+ tasks: Array<{
6
+ id: string;
7
+ status: string;
8
+ close_reason?: string;
9
+ }>;
10
+ }
11
+ interface PlanData {
12
+ title: string;
13
+ phases: PlanPhase[];
14
+ }
1
15
  interface CloseCommandOptions {
2
16
  sessionID?: string;
3
17
  skillReviewTimeoutMs?: number;
@@ -6,6 +20,16 @@ interface CloseKnowledgeEntry {
6
20
  created_at?: string;
7
21
  }
8
22
  declare function countSessionKnowledgeEntries(entries: CloseKnowledgeEntry[], sessionStart: string | undefined, fallbackCount: number): number;
23
+ declare function copyDirRecursive(src: string, dest: string): Promise<number>;
24
+ /**
25
+ * Guarantee all phases and tasks in a plan are marked complete/closed.
26
+ * Mutates planData in place. Returns actual IDs of newly closed phases and
27
+ * tasks so the caller can track only genuinely new closures (idempotent).
28
+ */
29
+ declare function guaranteeAllPlansComplete(planData: PlanData): {
30
+ closedPhaseIds: number[];
31
+ closedTaskIds: string[];
32
+ };
9
33
  /**
10
34
  * Handles /swarm close command - performs full terminal session finalization:
11
35
  * 0. Guarantee: mark all incomplete phases/tasks as closed
@@ -20,5 +44,7 @@ export declare function handleCloseCommand(directory: string, args: string[], op
20
44
  export declare const _internals: {
21
45
  countSessionKnowledgeEntries: typeof countSessionKnowledgeEntries;
22
46
  CLOSE_SKILL_REVIEW_TIMEOUT_MS: number;
47
+ guaranteeAllPlansComplete: typeof guaranteeAllPlansComplete;
48
+ copyDirRecursive: typeof copyDirRecursive;
23
49
  };
24
50
  export {};
@@ -497,6 +497,7 @@ export declare const KnowledgeConfigSchema: z.ZodObject<{
497
497
  hive_max_entries: z.ZodDefault<z.ZodNumber>;
498
498
  auto_promote_days: z.ZodDefault<z.ZodNumber>;
499
499
  max_inject_count: z.ZodDefault<z.ZodNumber>;
500
+ delegate_max_inject_count: z.ZodDefault<z.ZodNumber>;
500
501
  inject_char_budget: z.ZodDefault<z.ZodNumber>;
501
502
  context_budget_threshold: z.ZodOptional<z.ZodNumber>;
502
503
  max_lesson_display_chars: z.ZodDefault<z.ZodNumber>;
@@ -520,6 +521,13 @@ export declare const KnowledgeConfigSchema: z.ZodObject<{
520
521
  default_max_phases: z.ZodDefault<z.ZodNumber>;
521
522
  todo_max_phases: z.ZodDefault<z.ZodNumber>;
522
523
  sweep_enabled: z.ZodDefault<z.ZodBoolean>;
524
+ retrieval: z.ZodOptional<z.ZodObject<{
525
+ mmr_lambda: z.ZodDefault<z.ZodNumber>;
526
+ cold_start_bonus: z.ZodDefault<z.ZodNumber>;
527
+ cold_start_max_age_phases: z.ZodDefault<z.ZodNumber>;
528
+ synonym_min_cooccurrence: z.ZodDefault<z.ZodNumber>;
529
+ synonym_map_max_pairs: z.ZodDefault<z.ZodNumber>;
530
+ }, z.core.$strip>>;
523
531
  }, z.core.$strip>;
524
532
  export type KnowledgeConfig = z.infer<typeof KnowledgeConfigSchema>;
525
533
  export declare const MemoryConfigSchema: z.ZodObject<{
@@ -1264,6 +1272,7 @@ export declare const PluginConfigSchema: z.ZodObject<{
1264
1272
  hive_max_entries: z.ZodDefault<z.ZodNumber>;
1265
1273
  auto_promote_days: z.ZodDefault<z.ZodNumber>;
1266
1274
  max_inject_count: z.ZodDefault<z.ZodNumber>;
1275
+ delegate_max_inject_count: z.ZodDefault<z.ZodNumber>;
1267
1276
  inject_char_budget: z.ZodDefault<z.ZodNumber>;
1268
1277
  context_budget_threshold: z.ZodOptional<z.ZodNumber>;
1269
1278
  max_lesson_display_chars: z.ZodDefault<z.ZodNumber>;
@@ -1287,6 +1296,13 @@ export declare const PluginConfigSchema: z.ZodObject<{
1287
1296
  default_max_phases: z.ZodDefault<z.ZodNumber>;
1288
1297
  todo_max_phases: z.ZodDefault<z.ZodNumber>;
1289
1298
  sweep_enabled: z.ZodDefault<z.ZodBoolean>;
1299
+ retrieval: z.ZodOptional<z.ZodObject<{
1300
+ mmr_lambda: z.ZodDefault<z.ZodNumber>;
1301
+ cold_start_bonus: z.ZodDefault<z.ZodNumber>;
1302
+ cold_start_max_age_phases: z.ZodDefault<z.ZodNumber>;
1303
+ synonym_min_cooccurrence: z.ZodDefault<z.ZodNumber>;
1304
+ synonym_map_max_pairs: z.ZodDefault<z.ZodNumber>;
1305
+ }, z.core.$strip>>;
1290
1306
  }, z.core.$strip>>;
1291
1307
  memory: z.ZodOptional<z.ZodObject<{
1292
1308
  enabled: z.ZodDefault<z.ZodBoolean>;
@@ -0,0 +1,51 @@
1
+ /**
2
+ * Delegate ack collection (Swarm Learning System, Change 1 / Task 1.5).
3
+ *
4
+ * A `tool.execute.after` hook on the `Task` tool. After a delegated subagent
5
+ * returns, this reconciles the directives that were shown to it (recovered by
6
+ * parsing the `<delegate_knowledge_directives>` block out of the delegation
7
+ * prompt) against the ack markers in the subagent's transcript:
8
+ *
9
+ * - For every ack whose ID was actually shown, emit a receipt event of the
10
+ * matching type (applied / ignored / violated / n_a). Acks for IDs that were
11
+ * never shown are DROPPED (anti-spoofing).
12
+ * - For every CRITICAL directive that was shown but never acknowledged, emit a
13
+ * `violated` event with reason `unacknowledged` and append an audit line to
14
+ * `.swarm/unacknowledged-criticals.jsonl`.
15
+ *
16
+ * Stateless by design: it re-parses the prompt rather than relying on
17
+ * cross-hook mutable state, so it is safe under parallel delegations. Fail-open:
18
+ * never throws, never blocks.
19
+ */
20
+ export interface DelegateAckInput {
21
+ tool: unknown;
22
+ agent?: unknown;
23
+ sessionID?: unknown;
24
+ args?: unknown;
25
+ }
26
+ export interface DelegateAckOutput {
27
+ output?: unknown;
28
+ }
29
+ export interface CollectDelegateAcksResult {
30
+ emitted: Array<{
31
+ id: string;
32
+ type: string;
33
+ }>;
34
+ unacknowledgedCriticals: string[];
35
+ }
36
+ /**
37
+ * Core reconciliation used by both the runtime hook and tests. Returns a summary
38
+ * of what was emitted. Never throws.
39
+ */
40
+ export declare function collectDelegateAcks(params: {
41
+ directory: string;
42
+ prompt: string;
43
+ transcript: string;
44
+ agent: string;
45
+ sessionId?: string;
46
+ taskId?: string;
47
+ }): Promise<CollectDelegateAcksResult>;
48
+ /**
49
+ * `tool.execute.after` adapter. Reconciles delegate acks for a completed Task.
50
+ */
51
+ export declare function collectDelegateAcksAfter(directory: string, input: DelegateAckInput, output: DelegateAckOutput): Promise<void>;
@@ -0,0 +1,33 @@
1
+ /**
2
+ * Architect-side delegate directive injection (Swarm Learning System, Change 1 /
3
+ * Task 1.4).
4
+ *
5
+ * When the architect delegates via the `Task` tool, this `tool.execute.before`
6
+ * hook prepends the role-scoped `<delegate_knowledge_directives>` block to the
7
+ * subagent's prompt so the delegate sees the directives (and the ack contract)
8
+ * from its very first message. It mirrors the existing skill-injection pattern
9
+ * in src/index.ts, which already mutates `input.args.prompt`.
10
+ *
11
+ * This is ADVISORY (prompt enrichment): it must never throw or block a
12
+ * delegation. A retrieval failure simply leaves the prompt unchanged.
13
+ *
14
+ * NOTE on plan deviation: the implementation plan listed `src/agents/architect.ts`
15
+ * as the "delegation prompt builder". The architect is prompt-driven — real
16
+ * delegations are constructed by the model at runtime via the Task tool, so the
17
+ * code-accurate interception point is this hook, not the architect prompt
18
+ * template. The architect's own `<swarm_knowledge_directives>` injection is
19
+ * untouched.
20
+ */
21
+ import type { KnowledgeConfig } from './knowledge-types.js';
22
+ export interface DelegateInjectionInput {
23
+ tool: unknown;
24
+ agent?: unknown;
25
+ sessionID?: unknown;
26
+ args?: unknown;
27
+ }
28
+ /**
29
+ * Prepend the per-delegate directive block to a Task delegation's prompt.
30
+ * Returns the number of directives injected (0 when nothing was injected),
31
+ * primarily for test assertions. Never throws.
32
+ */
33
+ export declare function injectDelegateDirectivesBefore(directory: string, input: DelegateInjectionInput, config: KnowledgeConfig): Promise<number>;
@@ -8,15 +8,16 @@
8
8
  import type { KnowledgeApplicationResult } from './knowledge-types.js';
9
9
  export declare function resolveApplicationLogPath(directory: string): string;
10
10
  /**
11
- * Parse explicit knowledge-acknowledgment markers from architect text.
11
+ * Parse explicit knowledge-acknowledgment markers from architect/delegate text.
12
12
  * Recognised forms (case-insensitive, line-anchored or inline):
13
13
  * KNOWLEDGE_APPLIED: <id>
14
14
  * KNOWLEDGE_IGNORED: <id> reason=<reason>
15
15
  * KNOWLEDGE_VIOLATED: <id> reason=<reason>
16
+ * KNOWLEDGE_N_A: <id> reason=<reason> (delegate contract, Change 1)
16
17
  */
17
18
  export interface ParsedAcknowledgment {
18
19
  id: string;
19
- result: 'applied' | 'ignored' | 'violated';
20
+ result: 'applied' | 'ignored' | 'violated' | 'n_a';
20
21
  reason?: string;
21
22
  }
22
23
  export declare function parseAcknowledgments(text: string): ParsedAcknowledgment[];
@@ -38,7 +39,7 @@ export declare function recordKnowledgeShown(directory: string, ids: string[], c
38
39
  export declare function recordAcknowledgment(directory: string, ack: ParsedAcknowledgment, ctx: RecordContext): Promise<void>;
39
40
  /** Build the dedup key. Exported so test code and the runtime integration
40
41
  * share the exact format. */
41
- export declare function buildAckDedupKey(sessionId: string, id: string, result: KnowledgeApplicationResult, now?: Date): string;
42
+ export declare function buildAckDedupKey(sessionId: string, id: string, result: KnowledgeApplicationResult | 'n_a', now?: Date): string;
42
43
  /** Acknowledgment recording with dedup. Returns whether a record was actually
43
44
  * written (false on dedup hit). dedupSet should be swarmState.knowledgeAckDedup
44
45
  * in production; tests can pass a fresh Set. */
@@ -1,10 +1,68 @@
1
1
  /** Knowledge curator hook for opencode-swarm v6.17 two-tier knowledge system. */
2
- import type { KnowledgeConfig } from './knowledge-types.js';
2
+ import type { CuratorLLMDelegate } from './curator.js';
3
+ import type { ActionableDirectiveFields, KnowledgeConfig, SwarmKnowledgeEntry } from './knowledge-types.js';
4
+ import { type InsightCandidate } from './micro-reflector.js';
5
+ declare const seenRetroSections: Map<string, {
6
+ value: string;
7
+ timestamp: number;
8
+ }>;
9
+ /**
10
+ * Bound seenRetroSections to MAX_TRACKED_RETRO_SECTIONS entries, evicting the
11
+ * oldest-timestamp entries first. Called after every insert so the map can never
12
+ * exceed the cap regardless of how many distinct sessions appear within the
13
+ * 24-hour prune window.
14
+ */
15
+ declare function capSeenRetroSections(): void;
16
+ /** Record a seen-section hash and enforce the size cap in one step. */
17
+ declare function recordSeenRetroSection(key: string, value: string, timestamp: number): void;
3
18
  /**
4
19
  * Check if the input is a write operation targeting an evidence file.
5
20
  * Exported for testing purposes only.
6
21
  */
7
22
  export declare function isWriteToEvidenceFile(input: unknown): boolean;
23
+ /** Build the v3-schema enrichment prompt for a single prose lesson. */
24
+ export declare function buildV3EnrichmentPrompt(lesson: string, category: string, tags: string[]): string;
25
+ /**
26
+ * Parse + validate an enrichment response. Returns the sanitized fields when
27
+ * the output is shape-valid AND actionable, otherwise the list of missing
28
+ * requirements (for the RETRY follow-up). Untrusted-input hardened: only
29
+ * allowlisted fields are copied, then shape-validated by
30
+ * validateActionableFields (length caps, name patterns, injection checks).
31
+ */
32
+ export declare function parseV3EnrichmentResponse(text: string): {
33
+ fields: ActionableDirectiveFields;
34
+ } | {
35
+ missing: string[];
36
+ };
37
+ export interface EnrichmentQuotaOptions {
38
+ maxCalls: number;
39
+ window: 'utc' | 'local';
40
+ }
41
+ /**
42
+ * Enrich one prose lesson with v3 actionability fields via the curator LLM.
43
+ * One retry on schema failure (with a RETRY message naming the missing
44
+ * fields). Quota-gated per call via skill-improver-quota. Returns null when
45
+ * enrichment is unavailable (quota exhausted) or fails twice — the caller
46
+ * quarantines the entry. Never throws.
47
+ */
48
+ export declare function enrichLessonToV3(params: {
49
+ directory: string;
50
+ llmDelegate: CuratorLLMDelegate;
51
+ lesson: string;
52
+ category: string;
53
+ tags: string[];
54
+ quota?: EnrichmentQuotaOptions;
55
+ }): Promise<ActionableDirectiveFields | null>;
56
+ /** Max insight candidates folded into the store per phase boundary. */
57
+ export declare const MESO_INSIGHT_BATCH_LIMIT = 20;
58
+ /**
59
+ * Atomically consume up to `batchLimit` insight candidates from
60
+ * `.swarm/insight-candidates.jsonl`, writing back the unconsumed tail under the
61
+ * same lock so concurrent micro-reflection appends are never lost. Fail-open.
62
+ */
63
+ export declare function consumeInsightCandidates(directory: string, batchLimit?: number): Promise<InsightCandidate[]>;
64
+ /** Build a SwarmKnowledgeEntry from an already-v3-actionable insight candidate. */
65
+ export declare function insightCandidateToEntry(cand: InsightCandidate, projectName: string, phaseNumber: number, config: KnowledgeConfig): SwarmKnowledgeEntry;
8
66
  /**
9
67
  * Curate and store swarm knowledge entries from lessons.
10
68
  * @returns Promise resolving to an object with counts of stored, skipped, and rejected lessons.
@@ -13,10 +71,19 @@ export declare function curateAndStoreSwarm(lessons: string[], projectName: stri
13
71
  phase_number: number;
14
72
  }, directory: string, config: KnowledgeConfig, options?: {
15
73
  skipAutoPromotion?: boolean;
74
+ /**
75
+ * Change 4 (Task 4.2): LLM delegate used to enrich plain-prose lessons
76
+ * with v3 actionability fields before the Layer-5 gate. When absent,
77
+ * non-actionable lessons go straight to the unactionable queue.
78
+ */
79
+ llmDelegate?: CuratorLLMDelegate;
80
+ /** Quota knobs for enrichment calls (defaults: 10/day, utc window). */
81
+ enrichmentQuota?: EnrichmentQuotaOptions;
16
82
  }): Promise<{
17
83
  stored: number;
18
84
  skipped: number;
19
85
  rejected: number;
86
+ quarantined: number;
20
87
  }>;
21
88
  /**
22
89
  * Auto-promote swarm entries based on phase confirmations and age.
@@ -32,4 +99,9 @@ export declare const _internals: {
32
99
  curateAndStoreSwarm: typeof curateAndStoreSwarm;
33
100
  runAutoPromotion: typeof runAutoPromotion;
34
101
  createKnowledgeCuratorHook: typeof createKnowledgeCuratorHook;
102
+ seenRetroSections: typeof seenRetroSections;
103
+ recordSeenRetroSection: typeof recordSeenRetroSection;
104
+ capSeenRetroSections: typeof capSeenRetroSections;
105
+ MAX_TRACKED_RETRO_SECTIONS: number;
35
106
  };
107
+ export {};
@@ -0,0 +1,50 @@
1
+ /**
2
+ * Repeat-mistake escalator (Swarm Learning System, Change 3 / Task 3.2).
3
+ *
4
+ * When the same directive is violated >= {@link ESCALATION_THRESHOLD} times
5
+ * within {@link ESCALATION_WINDOW_DAYS} days (across sessions), it is
6
+ * auto-promoted to `directive_priority:'critical'` + `enforcement_mode:'enforce'`,
7
+ * its `escalation_history` gets a `repeat_violation` record, and an `escalation`
8
+ * event is emitted. Idempotent: an entry already at critical/enforce is never
9
+ * re-escalated, even on subsequent violations.
10
+ *
11
+ * Persistence goes through `rewriteKnowledge` (never a raw JSONL write). Fail-open:
12
+ * any error leaves the entry untouched and returns `escalated:false`.
13
+ */
14
+ import type { DirectivePriority } from './knowledge-types.js';
15
+ export declare const ESCALATION_WINDOW_DAYS = 30;
16
+ export declare const ESCALATION_THRESHOLD = 2;
17
+ export interface EscalationResult {
18
+ escalated: boolean;
19
+ entryId: string;
20
+ from?: DirectivePriority;
21
+ to?: DirectivePriority;
22
+ violationsInWindow?: number;
23
+ /** True when the entry was already critical/enforce (no-op, idempotent). */
24
+ alreadyEscalated?: boolean;
25
+ }
26
+ /**
27
+ * Evaluate and (if warranted) apply a repeat-violation escalation to a single
28
+ * entry. Call AFTER the triggering `violated` event has been persisted.
29
+ */
30
+ export declare function maybeEscalateOnViolation(directory: string, entryId: string, now?: Date): Promise<EscalationResult>;
31
+ export interface RecentEscalation {
32
+ entry_id: string;
33
+ from: string;
34
+ to: string;
35
+ reason: string;
36
+ at: string;
37
+ }
38
+ export declare const ESCALATION_DISPLAY_WINDOW_DAYS = 7;
39
+ /**
40
+ * Read escalation events from the last `windowDays` days, newest first. Used by
41
+ * the architect briefing and `/swarm status`. Fail-open: returns [] on error.
42
+ */
43
+ export declare function readRecentEscalations(directory: string, windowDays?: number, now?: Date): Promise<RecentEscalation[]>;
44
+ /**
45
+ * Render the architect-briefing "Recently Escalated" subsection. Returns null
46
+ * when there is nothing to show (no empty header).
47
+ */
48
+ export declare function buildEscalationBriefing(escalations: RecentEscalation[], windowDays?: number): string | null;
49
+ /** Run the escalator for several entry IDs (deduped). Never throws. */
50
+ export declare function escalateViolatedEntries(directory: string, entryIds: string[], now?: Date): Promise<EscalationResult[]>;
@@ -29,7 +29,11 @@ export declare const KNOWLEDGE_EVENT_SCHEMA_VERSION = 1;
29
29
  */
30
30
  export declare const MAX_EVENT_LOG_ENTRIES = 5000;
31
31
  /** Retrieval modes that surface knowledge to an agent. */
32
- export type RetrievalEventMode = 'manual' | 'auto_injection' | 'coder_context' | 'review_context' | 'curator';
32
+ export type RetrievalEventMode = 'manual' | 'auto_injection' | 'coder_context' | 'review_context' | 'curator'
33
+ /** Per-delegate directive injection (Change 1): a delegated subagent
34
+ * (coder/reviewer/test_engineer/sme/docs/designer/critic/curator) was shown
35
+ * the subset of directives scoped to its role + expected tools. */
36
+ | 'delegate_inject';
33
37
  /** A retrieval: a query returned a ranked set of knowledge entries. */
34
38
  export interface RetrievedEvent {
35
39
  type: 'retrieved';
@@ -52,7 +56,13 @@ export interface RetrievedEvent {
52
56
  }
53
57
  /** A receipt: an agent explicitly considered a specific knowledge entry. */
54
58
  export interface ReceiptEvent {
55
- type: 'acknowledged' | 'applied' | 'ignored' | 'contradicted' | 'violated';
59
+ type: 'acknowledged' | 'applied' | 'ignored' | 'contradicted' | 'violated'
60
+ /** Delegate decided a shown directive did not apply to its task (Change 1).
61
+ * Recorded for auditability; never penalizes the entry's outcome signal. */
62
+ | 'n_a'
63
+ /** Architect explicitly accepted an unresolved critical violation at
64
+ * phase_complete (Change 2, Task 2.4). Audit-only; never affects rollups. */
65
+ | 'override';
56
66
  schema_version?: number;
57
67
  event_id: string;
58
68
  trace_id: string;
@@ -63,6 +73,19 @@ export interface ReceiptEvent {
63
73
  task_id?: string;
64
74
  agent: string;
65
75
  reason?: string;
76
+ /**
77
+ * Origin discriminator (Change 2). Distinguishes reviewer-issued verdicts
78
+ * (`'reviewer'`) from delegate self-acks (`'delegate'`) without changing the
79
+ * `type`, so existing counter rollups (which switch on `type`) stay intact.
80
+ * A reviewer VERIFIED maps to type:'applied' with source:'reviewer'.
81
+ */
82
+ source?: 'delegate' | 'reviewer' | string;
83
+ /** Result of executing a directive's verification_predicate (Change 2). */
84
+ predicate_check?: {
85
+ predicate: string;
86
+ result: 'pass' | 'fail' | 'error';
87
+ detail: string;
88
+ };
66
89
  evidence?: {
67
90
  files?: string[];
68
91
  commands?: string[];
@@ -96,7 +119,19 @@ export interface ArchivedEvent {
96
119
  evidence?: string;
97
120
  previous_status?: string;
98
121
  }
99
- export type KnowledgeEvent = RetrievedEvent | ReceiptEvent | OutcomeEvent | ArchivedEvent;
122
+ /** An escalation: a directive was auto-promoted by the repeat-mistake escalator. */
123
+ export interface EscalationEvent {
124
+ type: 'escalation';
125
+ schema_version?: number;
126
+ event_id: string;
127
+ timestamp: string;
128
+ entry_id: string;
129
+ from: string;
130
+ to: string;
131
+ reason: string;
132
+ enforcement_mode?: string;
133
+ }
134
+ export type KnowledgeEvent = RetrievedEvent | ReceiptEvent | OutcomeEvent | ArchivedEvent | EscalationEvent;
100
135
  export type KnowledgeEventType = KnowledgeEvent['type'];
101
136
  /**
102
137
  * Event shape accepted by {@link appendKnowledgeEvent} / {@link recordKnowledgeEvent}.
@@ -154,6 +189,9 @@ export interface CounterRollup {
154
189
  ignored_count: number;
155
190
  violated_count: number;
156
191
  contradicted_count: number;
192
+ /** Count of explicit not-applicable decisions (Change 1). Auditable, neutral:
193
+ * never contributes to the outcome ranking signal. */
194
+ n_a_count: number;
157
195
  succeeded_after_shown_count: number;
158
196
  failed_after_shown_count: number;
159
197
  /**
@@ -164,7 +202,15 @@ export interface CounterRollup {
164
202
  partial_after_shown_count: number;
165
203
  last_applied_at?: string;
166
204
  last_acknowledged_at?: string;
205
+ /**
206
+ * The most recent violation timestamps for this entry (ISO 8601, newest
207
+ * first, capped at the last {@link MAX_VIOLATION_TIMESTAMPS}). Feeds the
208
+ * repeat-mistake escalator (Change 3).
209
+ */
210
+ violation_timestamps: string[];
167
211
  }
212
+ /** Cap on retained per-entry violation timestamps. */
213
+ export declare const MAX_VIOLATION_TIMESTAMPS = 10;
168
214
  /**
169
215
  * Recompute per-entry counters deterministically from the immutable event log,
170
216
  * optionally folding in legacy `knowledge-application.jsonl` records.
@@ -189,6 +235,20 @@ export interface CounterRollup {
189
235
  * @param legacyRecords Optional legacy application records (any order).
190
236
  */
191
237
  export declare function recomputeCounters(events: KnowledgeEvent[], legacyRecords?: KnowledgeApplicationRecord[]): Map<string, CounterRollup>;
238
+ /**
239
+ * Count how many of the given violation timestamps fall within `windowDays` of
240
+ * `now` (inclusive). Pure helper — deterministic given its inputs. Malformed
241
+ * timestamps are ignored.
242
+ */
243
+ export declare function countViolationsInWindow(timestamps: string[], windowDays: number, now?: Date): number;
244
+ /**
245
+ * Async convenience: count an entry's violations within a day-window. Counts
246
+ * directly from the event log + legacy application records so the result is
247
+ * INDEPENDENT of the {@link MAX_VIOLATION_TIMESTAMPS} display cap (the rollup's
248
+ * `violation_timestamps` keeps only the newest 10 and would undercount an entry
249
+ * with more in-window violations). Fail-open: returns 0 on error.
250
+ */
251
+ export declare function countEntryViolationsInWindow(directory: string, entryId: string, windowDays: number, now?: Date): Promise<number>;
192
252
  /**
193
253
  * Fail-open rollup reader for hot paths. Search and promotion use this instead
194
254
  * of stale persisted counters so `knowledge_receipt` feedback affects ranking
@@ -7,8 +7,76 @@
7
7
  */
8
8
  import { recordKnowledgeShown } from './knowledge-application.js';
9
9
  import { recordKnowledgeEvent } from './knowledge-events.js';
10
- import type { KnowledgeConfig, MessageWithParts } from './knowledge-types.js';
10
+ import type { RankedEntry } from './knowledge-reader.js';
11
+ import type { DirectivePriority, KnowledgeConfig, MessageWithParts } from './knowledge-types.js';
11
12
  import { searchKnowledge } from './search-knowledge.js';
13
+ /** Marker that uniquely identifies the delegate directive block in a transcript. */
14
+ export declare const DELEGATE_DIRECTIVE_BLOCK_TAG = "<delegate_knowledge_directives>";
15
+ /**
16
+ * Render a sanitized, deterministic `<delegate_knowledge_directives>` block for
17
+ * a delegated subagent (Change 1, Task 1.3). Entries are sorted by priority
18
+ * (critical first) then ID so the block is stable across runs and prompt caches
19
+ * remain warm. Returns null when there are no entries (no empty wrapper).
20
+ */
21
+ export declare function buildDelegateDirectiveBlock(entries: RankedEntry[], cfg: KnowledgeConfig): string | null;
22
+ /** A directive that was rendered into a delegate block, recovered by parsing. */
23
+ export interface ShownDelegateDirective {
24
+ id: string;
25
+ priority: DirectivePriority;
26
+ }
27
+ /**
28
+ * Recover the directive IDs (and priorities) that were rendered into a
29
+ * `<delegate_knowledge_directives>` block. Used by the ack-collector
30
+ * (Task 1.5) to reconcile a delegate's ack markers against what was actually
31
+ * shown — only IDs present here are honored, so a delegate cannot fabricate an
32
+ * ack for a directive it never received. Returns [] when no block is present.
33
+ */
34
+ export declare function parseDelegateDirectiveBlock(text: string): ShownDelegateDirective[];
35
+ export interface InjectForDelegateParams {
36
+ directory: string;
37
+ agent: string;
38
+ expectedTools?: string[];
39
+ taskTitle?: string;
40
+ sessionId?: string;
41
+ config: KnowledgeConfig;
42
+ /**
43
+ * Phase label recorded on the emitted `delegate_inject` event. Threading the
44
+ * real plan phase (rather than the task title) lets the reviewer verdict loop
45
+ * and the phase-complete gate window directives by phase (Change 2).
46
+ */
47
+ phase?: string;
48
+ /** Test seam: override the search function. Defaults to the live one. */
49
+ searchFn?: typeof searchKnowledge;
50
+ }
51
+ export interface InjectForDelegateResult {
52
+ entries: RankedEntry[];
53
+ trace_id: string;
54
+ }
55
+ /**
56
+ * Retrieve the subset of active knowledge directives scoped to a delegated
57
+ * subagent's role + expected tools (Change 1, Task 1.2). Emits a single
58
+ * `retrieved` event tagged `mode:'delegate_inject'` with the capped, in-scope
59
+ * entry IDs. Fail-open: any error yields an empty result.
60
+ */
61
+ export declare function injectForDelegate(params: InjectForDelegateParams): Promise<InjectForDelegateResult>;
62
+ /** Returns true if this agent is the architect (the sole intended recipient of orchestrator-tier knowledge injection). */
63
+ export declare function isOrchestratorAgent(agentName: string): boolean;
64
+ /**
65
+ * Returns true if this agent is a delegated subagent that should receive the
66
+ * per-agent directive block. Swarm prefixes (e.g. `mega_coder`) are stripped so
67
+ * prefixed agent names still match their canonical role.
68
+ */
69
+ export declare function isDelegatedAgent(agentName: string): boolean;
70
+ /** Returns the default expected-tools list for a delegated agent role. */
71
+ export declare function defaultExpectedToolsForAgent(agentName: string): string[];
72
+ /**
73
+ * Per-delegate scope match implementing the Change-1 OR semantics: an entry is
74
+ * in scope for a delegate when it is untargeted (no agent and no tool scope),
75
+ * OR its `applies_to_agents` includes the delegate's role, OR its
76
+ * `applies_to_tools` intersects the delegate's expected tools. Swarm prefixes
77
+ * are stripped on both sides so `mega_coder` matches a bare `coder`.
78
+ */
79
+ export declare function matchesDelegateScope(entry: Pick<RankedEntry, 'applies_to_agents' | 'applies_to_tools'>, role: string, expectedTools: readonly string[]): boolean;
12
80
  /**
13
81
  * Creates a knowledge injection hook that injects relevant knowledge into the
14
82
  * architect's message context at phase start. Supports caching for re-injection
@@ -43,9 +43,19 @@ export interface RetrievalOutcome {
43
43
  succeeded_after_shown_count?: number;
44
44
  /** v2: phase-failure count after a "shown" (replaces failed_after_count). */
45
45
  failed_after_shown_count?: number;
46
+ /** v3: recent violation timestamps (newest-first, capped) folded from the
47
+ * event-derived rollup. Surfaced for the repeat-mistake escalator. */
48
+ violation_timestamps?: string[];
46
49
  }
47
50
  /** v2: priority used by retrieval ranking and enforcement. */
48
51
  export type DirectivePriority = 'low' | 'medium' | 'high' | 'critical';
52
+ /** One automatic escalation applied to a directive (Change 3). */
53
+ export interface DirectiveEscalationRecord {
54
+ from: DirectivePriority;
55
+ to: DirectivePriority;
56
+ reason: 'repeat_violation' | string;
57
+ at: string;
58
+ }
49
59
  /** v2: optional actionable-directive metadata attached to a knowledge entry. */
50
60
  export interface ActionableDirectiveFields {
51
61
  /** Trigger phrases that surface this entry (e.g. "coder delegation modifying source"). */
@@ -60,6 +70,15 @@ export interface ActionableDirectiveFields {
60
70
  applies_to_tools?: string[];
61
71
  /** Reviewer/test-engineer/runtime checks the directive expects. */
62
72
  verification_checks?: string[];
73
+ /**
74
+ * A single machine-checkable verification predicate (Change 2). DSL:
75
+ * grep:<regex>:<path-glob> pass when ripgrep finds zero matches
76
+ * tool:<argv> pass when the (allowlisted, shell-free) command exits 0
77
+ * file_not_modified:<path> pass when the path is unchanged in the working tree
78
+ * file_modified:<path> pass when the path is changed in the working tree
79
+ * Runs fail-closed (parse error → error) with a hard 15s timeout, no shell.
80
+ */
81
+ verification_predicate?: string;
63
82
  /** Source pointers (file:line, plan section, etc.). Sanitized. */
64
83
  source_refs?: string[];
65
84
  /** UUIDs of source knowledge entries (for derived/clustered entries). */
@@ -70,6 +89,14 @@ export interface ActionableDirectiveFields {
70
89
  generated_skill_path?: string;
71
90
  /** Directive priority for ranking/enforcement. */
72
91
  directive_priority?: DirectivePriority;
92
+ /**
93
+ * Enforcement posture (Change 3). `'enforce'` makes the directive block at the
94
+ * point of violation; `'warn'` only records. Auto-set to `'enforce'` by the
95
+ * repeat-mistake escalator.
96
+ */
97
+ enforcement_mode?: 'warn' | 'enforce';
98
+ /** Audit trail of automatic escalations applied to this directive (Change 3). */
99
+ escalation_history?: DirectiveEscalationRecord[];
73
100
  /** ISO 8601 timestamp of last explicit application. */
74
101
  last_applied_at?: string;
75
102
  /** ISO 8601 timestamp of last explicit acknowledgment. */
@@ -83,7 +110,10 @@ export interface KnowledgeEntryBase extends ActionableDirectiveFields {
83
110
  tags: string[];
84
111
  scope: string;
85
112
  confidence: number;
86
- status: 'candidate' | 'established' | 'promoted' | 'archived' | 'quarantined';
113
+ status: 'candidate' | 'established' | 'promoted' | 'archived' | 'quarantined'
114
+ /** Change 4: failed the actionability layer (no predicate or no scope tag).
115
+ * Held out of the active store pending hardening by the skill-improver. */
116
+ | 'quarantined_unactionable';
87
117
  confirmed_by: PhaseConfirmationRecord[] | ProjectConfirmationRecord[];
88
118
  retrieval_outcomes: RetrievalOutcome;
89
119
  schema_version: number;
@@ -128,6 +158,8 @@ export interface KnowledgeConfig {
128
158
  auto_promote_days: number;
129
159
  /** Maximum knowledge entries to inject per architect message. Default: 5 */
130
160
  max_inject_count: number;
161
+ /** Maximum knowledge directives injected into a delegated subagent's prompt. Default: 8 */
162
+ delegate_max_inject_count?: number;
131
163
  /** Maximum total chars for the entire injection block. Default: 2000 */
132
164
  inject_char_budget?: number;
133
165
  /** Minimum headroom chars required before knowledge injection activates. Default: 300 */
@@ -172,6 +204,14 @@ export interface KnowledgeConfig {
172
204
  todo_max_phases: number;
173
205
  /** Enable age-based sweep of knowledge entries. Default: true */
174
206
  sweep_enabled: boolean;
207
+ /** Change 5: retrieval-upgrade tuning (MMR / cold-start / synonyms). */
208
+ retrieval?: {
209
+ mmr_lambda?: number;
210
+ cold_start_bonus?: number;
211
+ cold_start_max_age_phases?: number;
212
+ synonym_min_cooccurrence?: number;
213
+ synonym_map_max_pairs?: number;
214
+ };
175
215
  }
176
216
  export interface MessageInfo {
177
217
  role: string;