opencode-swarm 7.121.4 → 7.122.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/dist/cli/{config-doctor-404c8mf8.js → config-doctor-3ksh1534.js} +2 -2
- package/dist/cli/{core-xnwasfpc.js → core-cwgb7ev8.js} +1 -1
- package/dist/cli/{curation-policy-10wnhpwn.js → curation-policy-4j4qce5a.js} +5 -5
- package/dist/cli/{curator-llm-factory-6rafny5e.js → curator-llm-factory-x769hn66.js} +22 -20
- package/dist/cli/{curator-3azybqrw.js → curator-qfh07497.js} +22 -20
- package/dist/cli/{evidence-summary-service-k14ykm03.js → evidence-summary-service-96ndczbk.js} +7 -5
- package/dist/cli/{gate-evidence-tbpezk28.js → gate-evidence-xqks3kk2.js} +3 -3
- package/dist/cli/{guardrail-explain-d1m747g5.js → guardrail-explain-kj0e9r25.js} +23 -21
- package/dist/cli/{guardrail-log-dhpp0kmn.js → guardrail-log-z291m4gw.js} +3 -3
- package/dist/cli/{hive-promoter-4xnj3fdk.js → hive-promoter-00mktxkk.js} +22 -20
- package/dist/cli/{index-zvae4m8g.js → index-17eybc3z.js} +1 -1
- package/dist/cli/{index-kyvg2cmp.js → index-19zn67q6.js} +1 -1
- package/dist/cli/{index-rbfq77sz.js → index-2j25br0p.js} +12 -10
- package/dist/cli/{index-9xpgytj9.js → index-3rr0ese8.js} +1 -1
- package/dist/cli/{index-x4fwtd59.js → index-5he0kwnx.js} +3 -3
- package/dist/cli/{index-982hhpcm.js → index-6srk9a5q.js} +2 -2
- package/dist/cli/{index-qg11yf8q.js → index-6xnxz6z0.js} +1 -1
- package/dist/cli/{index-emkb0bbe.js → index-7cspygmb.js} +277 -673
- package/dist/cli/{index-5a3xsnzg.js → index-cqsak7bf.js} +2 -2
- package/dist/cli/index-ctpgsj84.js +547 -0
- package/dist/cli/index-d6h5hq91.js +564 -0
- package/dist/cli/{index-vqcgmy4y.js → index-det5jwfk.js} +1 -1
- package/dist/cli/{index-35xyj7gn.js → index-dywekeen.js} +28 -5
- package/dist/cli/{index-wtn8wf7h.js → index-gw3m5fw0.js} +1 -1
- package/dist/cli/{index-j8349ac0.js → index-hns7xjm7.js} +2 -2
- package/dist/cli/{index-ft6jw816.js → index-j9kxwshw.js} +5 -5
- package/dist/cli/{index-2k6z335c.js → index-jm81nhks.js} +24 -22
- package/dist/cli/{index-q0fv0xec.js → index-kanrv3sv.js} +280 -119
- package/dist/cli/{index-db82jxt7.js → index-m0bmh3w0.js} +4 -4
- package/dist/cli/index-m1abzg93.js +68 -0
- package/dist/cli/{index-0f800qg7.js → index-n2712byd.js} +6 -6
- package/dist/cli/{index-3jvqw5hy.js → index-q27bajqb.js} +1 -1
- package/dist/cli/{index-qt2yaghg.js → index-vcgfqd8f.js} +1 -63
- package/dist/cli/{index-tftv9xh9.js → index-wr8qgpz5.js} +1 -1
- package/dist/cli/index.js +22 -20
- package/dist/cli/{knowledge-escalator-8ajq1fhb.js → knowledge-escalator-dyxsm78k.js} +6 -6
- package/dist/cli/{knowledge-events-2sjy3aa7.js → knowledge-events-36q6nvae.js} +6 -4
- package/dist/cli/{knowledge-link-sy85fw3w.js → knowledge-link-4yd2z8ev.js} +3 -3
- package/dist/cli/{knowledge-store-27cesthc.js → knowledge-store-e07b4s54.js} +4 -4
- package/dist/cli/{knowledge-validator-9keh3p8j.js → knowledge-validator-sfyf7wn2.js} +7 -7
- package/dist/cli/pr-subscriptions-x653151h.js +1 -1
- package/dist/cli/{scan-cursor-qmsmmg1b.js → scan-cursor-hm0aqqae.js} +5 -5
- package/dist/cli/{schema-vwxpsk6j.js → schema-13bnng2n.js} +1 -1
- package/dist/cli/scope-persistence-d9erwnvb.js +36 -0
- package/dist/cli/{skill-generator-hkyxdc3j.js → skill-generator-g6r52x94.js} +8 -8
- package/dist/config/constants.d.ts +3 -2
- package/dist/hooks/cohort-cache.d.ts +44 -0
- package/dist/hooks/delegation-gate.d.ts +19 -1
- package/dist/hooks/guardrails/nontransient-circuit.d.ts +47 -0
- package/dist/hooks/hive-promoter.d.ts +4 -3
- package/dist/hooks/host-boundary.d.ts +147 -0
- package/dist/hooks/incremental-verify.d.ts +3 -0
- package/dist/hooks/knowledge-events.d.ts +25 -2
- package/dist/hooks/knowledge-injector.d.ts +9 -1
- package/dist/hooks/knowledge-receipt-validator.d.ts +98 -0
- package/dist/hooks/micro-reflector.d.ts +3 -0
- package/dist/hooks/pr-auto-subscribe.d.ts +3 -0
- package/dist/hooks/promotion-evidence-store.d.ts +33 -0
- package/dist/hooks/scope-guard.d.ts +9 -2
- package/dist/hooks/write-target-resolver.d.ts +30 -0
- package/dist/index.js +423 -380
- package/dist/sandbox/win32/restricted-environment-executor.d.ts +3 -2
- package/dist/scope/scope-binding.d.ts +89 -0
- package/dist/scope/scope-persistence.d.ts +53 -12
- package/dist/services/knowledge-diagnostics.d.ts +12 -0
- package/dist/session/snapshot-writer.d.ts +5 -0
- package/dist/state.d.ts +36 -1
- package/dist/tools/declare-scope.d.ts +5 -1
- package/dist/tools/file-extractor-planner.d.ts +31 -0
- package/dist/tools/file-extractor.d.ts +2 -7
- package/package.json +1 -1
- package/dist/cli/index-51gg9947.js +0 -254
- package/dist/cli/scope-persistence-mfr36yc9.js +0 -20
- package/dist/cli/{index-h07wn84h.js → index-7mkpsw6g.js} +3 -3
- package/dist/cli/{pending-delegations-0z3znsec.js → pending-delegations-68cbaqv2.js} +1 -1
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { type NonTransientCircuitState, type NonTransientErrorCategory, type PendingToolExecution } from '../../state';
|
|
2
|
+
export type ToolOutcome = {
|
|
3
|
+
kind: 'success';
|
|
4
|
+
signal: string;
|
|
5
|
+
} | {
|
|
6
|
+
kind: 'neutral';
|
|
7
|
+
signal: string;
|
|
8
|
+
} | {
|
|
9
|
+
kind: 'unknown';
|
|
10
|
+
signal: string;
|
|
11
|
+
} | {
|
|
12
|
+
kind: 'failure';
|
|
13
|
+
signal: string;
|
|
14
|
+
} | {
|
|
15
|
+
kind: 'fatal';
|
|
16
|
+
category: NonTransientErrorCategory;
|
|
17
|
+
signal: string;
|
|
18
|
+
};
|
|
19
|
+
type ToolAfterInput = {
|
|
20
|
+
tool: string;
|
|
21
|
+
sessionID: string;
|
|
22
|
+
callID: string;
|
|
23
|
+
args?: Record<string, unknown>;
|
|
24
|
+
};
|
|
25
|
+
type ToolAfterOutput = {
|
|
26
|
+
title: string;
|
|
27
|
+
output: string;
|
|
28
|
+
metadata: unknown;
|
|
29
|
+
[key: string]: unknown;
|
|
30
|
+
};
|
|
31
|
+
declare function isNeutralExitOne(command: string): boolean;
|
|
32
|
+
declare function classifyFatalSignal(signal: string, sandboxWrapped: boolean): NonTransientErrorCategory | null;
|
|
33
|
+
export declare function classifyToolOutcome(input: ToolAfterInput, output: ToolAfterOutput, correlation?: PendingToolExecution): ToolOutcome;
|
|
34
|
+
export declare function recordNonTransientFailure(sessionID: string, category: NonTransientErrorCategory, signal: string): NonTransientCircuitState | null;
|
|
35
|
+
export declare function clearNonTransientCircuit(sessionID: string): void;
|
|
36
|
+
export declare function nonTransientHardStopMessage(circuit: NonTransientCircuitState): string;
|
|
37
|
+
export declare function assertNonTransientCircuitAllowsTool(sessionID: string): void;
|
|
38
|
+
export declare function rememberToolExecution(sessionID: string, callID: string, tool: string, originalCommand: string): void;
|
|
39
|
+
export declare function isToolExecutionCurrent(sessionID: string, execution: PendingToolExecution): boolean;
|
|
40
|
+
export declare function markToolExecutionSandboxWrapped(sessionID: string, callID: string): void;
|
|
41
|
+
export declare function takeToolExecution(sessionID: string, callID: string): PendingToolExecution | undefined;
|
|
42
|
+
export declare function forgetToolExecution(sessionID: string, callID: string): void;
|
|
43
|
+
export declare const _test_exports: {
|
|
44
|
+
isNeutralExitOne: typeof isNeutralExitOne;
|
|
45
|
+
classifyFatalSignal: typeof classifyFatalSignal;
|
|
46
|
+
};
|
|
47
|
+
export {};
|
|
@@ -81,9 +81,10 @@ export declare const _internals: {
|
|
|
81
81
|
transactHiveStore: typeof transactHiveStore;
|
|
82
82
|
validateLesson: typeof validateLesson;
|
|
83
83
|
authorizeCuration: typeof authorizeCuration;
|
|
84
|
-
/** Loads validated terminal-application evidence per swarm entry id
|
|
85
|
-
*
|
|
86
|
-
|
|
84
|
+
/** (#1849) Loads validated terminal-application evidence per swarm entry id
|
|
85
|
+
* from .swarm/knowledge-promotion-evidence.jsonl. Empty when no validated
|
|
86
|
+
* receipts exist yet (conservative: no synthetic credit). */
|
|
87
|
+
loadPromotionEvidence: (directory: string) => Promise<Record<string, PromotionEvidenceRecord[]>>;
|
|
87
88
|
/** Loads the default KnowledgeConfig (schema defaults) for manual promotion
|
|
88
89
|
* paths when the command did not load one. */
|
|
89
90
|
loadDefaultKnowledgeConfig: () => {
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Host-boundary adapter (issue #1849).
|
|
3
|
+
*
|
|
4
|
+
* The single place that translates real OpenCode SDK callback payloads into a
|
|
5
|
+
* stable, typed internal context. Every downstream knowledge/delegation hook
|
|
6
|
+
* reads from this adapter — never directly from the raw `input`/`output`
|
|
7
|
+
* callback arguments. This eliminates the class of defect where hooks guessed
|
|
8
|
+
* SDK payload shapes (`input.agent`, `input.args`, synthetic `role:'system'`
|
|
9
|
+
* messages) that the host never provides.
|
|
10
|
+
*
|
|
11
|
+
* Authoritative SDK contract (`@opencode-ai/plugin@1.x`, `Hooks` interface):
|
|
12
|
+
*
|
|
13
|
+
* tool.execute.before: input { tool, sessionID, callID }
|
|
14
|
+
* output { args } ← mutable tool args
|
|
15
|
+
* tool.execute.after: input { tool, sessionID, callID }
|
|
16
|
+
* output { title, output, metadata }
|
|
17
|
+
* experimental.chat.messages.transform:
|
|
18
|
+
* input {} ← no sessionID/agent
|
|
19
|
+
* output { messages: { info: Message, parts }[] }
|
|
20
|
+
* experimental.chat.system.transform:
|
|
21
|
+
* input { sessionID?, model }
|
|
22
|
+
* output { system: string[] }
|
|
23
|
+
* chat.message: input { sessionID, agent?, ... } ← agent IS provided here
|
|
24
|
+
*
|
|
25
|
+
* `Message = UserMessage | AssistantMessage` — there is NO `role:'system'`
|
|
26
|
+
* message variant. `UserMessage` carries `agent` + `sessionID`; `AssistantMessage`
|
|
27
|
+
* carries `sessionID` only. System content is delivered via the separate
|
|
28
|
+
* `experimental.chat.system.transform` hook.
|
|
29
|
+
*
|
|
30
|
+
* Identity recovery strategy (verified against the SDK contract):
|
|
31
|
+
* - For `tool.execute.*` and `experimental.chat.messages.transform`, the
|
|
32
|
+
* reliable identity source is `swarmState.activeAgent.get(sessionID)`, which
|
|
33
|
+
* is populated by the `chat.message` hook (where `agent` IS provided).
|
|
34
|
+
* - For `messages.transform`, the last user message's `info.agent` is a
|
|
35
|
+
* first-turn fallback when `swarmState.activeAgent` has no entry yet.
|
|
36
|
+
* - Multi-swarm prefixed names (`cohort_architect`) are canonicalized via
|
|
37
|
+
* `stripKnownSwarmPrefix` (suffix-based; handles any user-defined prefix).
|
|
38
|
+
*/
|
|
39
|
+
/** Resolved context for `tool.execute.before` / `tool.execute.after`. */
|
|
40
|
+
export interface ToolBoundaryContext {
|
|
41
|
+
tool: string;
|
|
42
|
+
sessionID: string;
|
|
43
|
+
callID: string;
|
|
44
|
+
/** Active agent for this session (from swarmState.activeAgent; architect fallback). */
|
|
45
|
+
agent: string;
|
|
46
|
+
/** Canonicalized role, e.g. `architect` for `cohort_architect`. */
|
|
47
|
+
callerRole: string;
|
|
48
|
+
/**
|
|
49
|
+
* Mutable tool arguments.
|
|
50
|
+
* - toolBefore: `output.args` (the SDK mutation target).
|
|
51
|
+
* - toolAfter: `getStoredInputArgs(callID)` (the snapshot taken in toolBefore
|
|
52
|
+
* by `guardrails/tool-before.ts`).
|
|
53
|
+
* `null` when absent (the host did not supply args, or the snapshot was
|
|
54
|
+
* already cleaned up).
|
|
55
|
+
*/
|
|
56
|
+
args: Record<string, unknown> | null;
|
|
57
|
+
/** True when the caller canonicalizes to the orchestrator/architect role. */
|
|
58
|
+
isArchitect: boolean;
|
|
59
|
+
}
|
|
60
|
+
/** Resolved context for `experimental.chat.messages.transform`. */
|
|
61
|
+
export interface MessageTransformContext {
|
|
62
|
+
sessionID: string | undefined;
|
|
63
|
+
/** Active agent (swarmState.activeAgent primary; last user message fallback). */
|
|
64
|
+
agent: string | undefined;
|
|
65
|
+
callerRole: string | undefined;
|
|
66
|
+
isArchitect: boolean;
|
|
67
|
+
isDelegate: boolean;
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Minimal shape of `output.messages[].info` we read. The real SDK `Message`
|
|
71
|
+
* union carries many more fields; we only depend on `role`, `agent`
|
|
72
|
+
* (UserMessage only), and `sessionID`.
|
|
73
|
+
*/
|
|
74
|
+
export interface MessageInfoLike {
|
|
75
|
+
role?: string;
|
|
76
|
+
agent?: string;
|
|
77
|
+
sessionID?: string;
|
|
78
|
+
}
|
|
79
|
+
export interface MessageArrayLike {
|
|
80
|
+
messages?: Array<{
|
|
81
|
+
info?: MessageInfoLike;
|
|
82
|
+
}>;
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Resolve the active agent for a sessionID.
|
|
86
|
+
*
|
|
87
|
+
* PRIMARY: `swarmState.activeAgent.get(sessionID)` — set reliably by the
|
|
88
|
+
* `chat.message` hook. FALLBACK: `ORCHESTRATOR_NAME` ('architect'), mirroring
|
|
89
|
+
* the existing pre-#1849 behavior at `src/index.ts:2039-2041` (when no active
|
|
90
|
+
* agent is mapped, the session is treated as the primary/architect).
|
|
91
|
+
*
|
|
92
|
+
* Never throws. Emits a bounded, debug-gated diagnostic only when the session
|
|
93
|
+
* has no mapped agent (informational — the fallback is intentional, not an
|
|
94
|
+
* error).
|
|
95
|
+
*/
|
|
96
|
+
declare function resolveAgent(sessionID: string | undefined): string;
|
|
97
|
+
declare function isPlainObject(v: unknown): v is Record<string, unknown>;
|
|
98
|
+
declare function toArgs(v: unknown): Record<string, unknown> | null;
|
|
99
|
+
/**
|
|
100
|
+
* Build the `tool.execute.before` context.
|
|
101
|
+
*
|
|
102
|
+
* Reads `agent` from `swarmState.activeAgent` (NOT `input.agent`, which the
|
|
103
|
+
* host does not provide) and `args` from `output.args` (NOT `input.args`).
|
|
104
|
+
*/
|
|
105
|
+
export declare function resolveToolBeforeContext(input: {
|
|
106
|
+
tool: string;
|
|
107
|
+
sessionID: string;
|
|
108
|
+
callID: string;
|
|
109
|
+
}, output: {
|
|
110
|
+
args?: unknown;
|
|
111
|
+
}): ToolBoundaryContext;
|
|
112
|
+
/**
|
|
113
|
+
* Build the `tool.execute.after` context.
|
|
114
|
+
*
|
|
115
|
+
* `args` is recovered from the snapshot taken in toolBefore via
|
|
116
|
+
* `setStoredInputArgs(callID, output.args)` (`guardrails/tool-before.ts`). The
|
|
117
|
+
* SDK `tool.execute.after` input has no `args` field and the output carries only
|
|
118
|
+
* `title`/`output`/`metadata`, so the snapshot is the only correct source.
|
|
119
|
+
*/
|
|
120
|
+
export declare function resolveToolAfterContext(input: {
|
|
121
|
+
tool: string;
|
|
122
|
+
sessionID: string;
|
|
123
|
+
callID: string;
|
|
124
|
+
}): ToolBoundaryContext;
|
|
125
|
+
/**
|
|
126
|
+
* Build the `experimental.chat.messages.transform` context.
|
|
127
|
+
*
|
|
128
|
+
* The SDK `input` is `{}`, so session/agent identity is recovered from
|
|
129
|
+
* `output.messages[].info`:
|
|
130
|
+
* - `sessionID` from any message's `info.sessionID` (every `Message` carries it).
|
|
131
|
+
* - `agent` PRIMARY from `swarmState.activeAgent.get(sessionID)`; FALLBACK from
|
|
132
|
+
* the LAST user message's `info.agent` (`UserMessage` carries `agent`).
|
|
133
|
+
*
|
|
134
|
+
* Critically, this NEVER searches for a `role:'system'` message — the SDK
|
|
135
|
+
* `Message` union has no system-role variant, and looking for one was the root
|
|
136
|
+
* cause of the dark-in-production architect injection (#1768/#1849).
|
|
137
|
+
*/
|
|
138
|
+
export declare function resolveMessageTransformContext(output: MessageArrayLike): MessageTransformContext;
|
|
139
|
+
/** Like resolveAgent but returns undefined instead of the orchestrator fallback. */
|
|
140
|
+
declare function resolveAgentOptional(sessionID: string | undefined): string | undefined;
|
|
141
|
+
export declare const _internals: {
|
|
142
|
+
resolveAgent: typeof resolveAgent;
|
|
143
|
+
resolveAgentOptional: typeof resolveAgentOptional;
|
|
144
|
+
toArgs: typeof toArgs;
|
|
145
|
+
isPlainObject: typeof isPlainObject;
|
|
146
|
+
};
|
|
147
|
+
export {};
|
|
@@ -11,6 +11,9 @@ export interface IncrementalVerifyHook {
|
|
|
11
11
|
tool: string;
|
|
12
12
|
sessionID: string;
|
|
13
13
|
args?: unknown;
|
|
14
|
+
/** (#1849) SDK tool.execute.after input carries callID (not args); used
|
|
15
|
+
* to recover the snapshot args via resolveToolAfterContext. */
|
|
16
|
+
callID?: string;
|
|
14
17
|
}, output: {
|
|
15
18
|
output?: unknown;
|
|
16
19
|
args?: unknown;
|
|
@@ -64,11 +64,26 @@ export interface ReceiptEvent {
|
|
|
64
64
|
| 'n_a'
|
|
65
65
|
/** Architect explicitly accepted an unresolved critical violation at
|
|
66
66
|
* phase_complete (Change 2, Task 2.4). Audit-only; never affects rollups. */
|
|
67
|
-
| 'override'
|
|
67
|
+
| 'override'
|
|
68
|
+
/**
|
|
69
|
+
* Terminal accounting event for an EMPTY retrieval (issue #1849): an agent
|
|
70
|
+
* considered a trace that surfaced no relevant knowledge and explicitly filed
|
|
71
|
+
* `no_relevant_knowledge`. This closes the "every retrieval attempt has one
|
|
72
|
+
* durable terminal accounting path, including empty result" contract. Audit
|
|
73
|
+
* only — `recomputeCounters` intentionally does NOT mutate any per-entry
|
|
74
|
+
* counter (there is no `knowledge_id` to credit; this is a trace-level
|
|
75
|
+
* tombstone, not application credit).
|
|
76
|
+
*/
|
|
77
|
+
| 'no_relevant';
|
|
68
78
|
schema_version?: number;
|
|
69
79
|
event_id: string;
|
|
70
80
|
trace_id: string;
|
|
71
|
-
|
|
81
|
+
/**
|
|
82
|
+
* The considered knowledge entry. Optional for the `no_relevant` terminal
|
|
83
|
+
* (issue #1849), which is a trace-level tombstone for an empty retrieval and
|
|
84
|
+
* references no specific entry.
|
|
85
|
+
*/
|
|
86
|
+
knowledge_id?: string;
|
|
72
87
|
timestamp: string;
|
|
73
88
|
session_id: string;
|
|
74
89
|
phase?: string;
|
|
@@ -300,6 +315,14 @@ export declare function recomputeCounters(events: KnowledgeEvent[], legacyRecord
|
|
|
300
315
|
* timestamps are ignored.
|
|
301
316
|
*/
|
|
302
317
|
export declare function countViolationsInWindow(timestamps: string[], windowDays: number, now?: Date): number;
|
|
318
|
+
/**
|
|
319
|
+
* Count the durable `no_relevant` terminal events (issue #1849) in the given
|
|
320
|
+
* event list — the trace-level tombstones recording that a retrieval surfaced
|
|
321
|
+
* nothing relevant and was explicitly accounted for. Pure helper for
|
|
322
|
+
* diagnostics (`/swarm status`, `knowledge_recall debug`). NOT a per-entry
|
|
323
|
+
* counter; there is no `knowledge_id` to credit.
|
|
324
|
+
*/
|
|
325
|
+
export declare function countEmptyTraceTerminals(events: KnowledgeEvent[]): number;
|
|
303
326
|
/**
|
|
304
327
|
* Async convenience: count an entry's violations within a day-window. Counts
|
|
305
328
|
* directly from the event log + legacy application records so the result is
|
|
@@ -21,7 +21,7 @@ export declare const DELEGATE_DIRECTIVE_BLOCK_TAG = "<delegate_knowledge_directi
|
|
|
21
21
|
* (critical first) then ID so the block is stable across runs and prompt caches
|
|
22
22
|
* remain warm. Returns null when there are no entries (no empty wrapper).
|
|
23
23
|
*/
|
|
24
|
-
export declare function buildDelegateDirectiveBlock(entries: RankedEntry[], cfg: KnowledgeConfig): string | null;
|
|
24
|
+
export declare function buildDelegateDirectiveBlock(entries: RankedEntry[], cfg: KnowledgeConfig, traceId?: string): string | null;
|
|
25
25
|
/** A directive that was rendered into a delegate block, recovered by parsing. */
|
|
26
26
|
export interface ShownDelegateDirective {
|
|
27
27
|
id: string;
|
|
@@ -35,6 +35,14 @@ export interface ShownDelegateDirective {
|
|
|
35
35
|
* ack for a directive it never received. Returns [] when no block is present.
|
|
36
36
|
*/
|
|
37
37
|
export declare function parseDelegateDirectiveBlock(text: string): ShownDelegateDirective[];
|
|
38
|
+
/**
|
|
39
|
+
* Recover the `trace_id` rendered into a `<delegate_knowledge_directives>` block
|
|
40
|
+
* (issue #1849 RC-4). Returns undefined when the block is absent or when it
|
|
41
|
+
* predates the trace_id header (backward-compatible with older prompts). The
|
|
42
|
+
* delegate-ack-collector uses this to attribute acks to the ORIGINAL retrieval
|
|
43
|
+
* trace instead of minting an untied one.
|
|
44
|
+
*/
|
|
45
|
+
export declare function parseDelegateDirectiveTraceId(text: string): string | undefined;
|
|
38
46
|
export interface InjectForDelegateParams {
|
|
39
47
|
directory: string;
|
|
40
48
|
agent: string;
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared receipt validator (issue #1849).
|
|
3
|
+
*
|
|
4
|
+
* One validator that enforces the terminal-receipt contract for BOTH the
|
|
5
|
+
* `knowledge_receipt` tool AND the `delegate-ack-collector`. Reads the
|
|
6
|
+
* authoritative event log and rejects forged / expired / conflicting /
|
|
7
|
+
* non-trace receipts while keeping idempotent retries free of double-counting.
|
|
8
|
+
*
|
|
9
|
+
* Authority contract (per issue #1849 §3):
|
|
10
|
+
* - trace/result delivery proves shown/retrieved only;
|
|
11
|
+
* - a validated terminal receipt is the durable audit outcome;
|
|
12
|
+
* - applied counters derive ONLY from validated `applied` receipts;
|
|
13
|
+
* - ignored/contradicted/no_relevant remain visible but are not application credit.
|
|
14
|
+
*
|
|
15
|
+
* Uniqueness grain: ONE terminal per (trace_id, knowledge_id). A trace surfaces a
|
|
16
|
+
* set of entries; for each entry at most one terminal outcome is accepted.
|
|
17
|
+
* Idempotent retry of the SAME outcome is accepted (not re-emitted, not
|
|
18
|
+
* double-counted); a DIFFERENT outcome for the same (trace_id, knowledge_id)
|
|
19
|
+
* is a conflicting-terminal rejection. The delegate ack path legitimately
|
|
20
|
+
* emits multiple terminals per trace (one per shown directive) — that is fine
|
|
21
|
+
* because each directive has a distinct knowledge_id.
|
|
22
|
+
*/
|
|
23
|
+
import { type KnowledgeEvent, type RetrievedEvent } from './knowledge-events.js';
|
|
24
|
+
/** Terminal outcomes the validator accepts. */
|
|
25
|
+
export type ReceiptOutcome = 'applied' | 'ignored' | 'contradicted' | 'violated' | 'n_a' | 'no_relevant';
|
|
26
|
+
/** A single item being filed in a receipt. */
|
|
27
|
+
export interface ReceiptItem {
|
|
28
|
+
id: string;
|
|
29
|
+
outcome: Exclude<ReceiptOutcome, 'no_relevant'>;
|
|
30
|
+
reason?: string;
|
|
31
|
+
}
|
|
32
|
+
export interface ReceiptValidationContext {
|
|
33
|
+
directory: string;
|
|
34
|
+
/** The retrieval trace this receipt accounts for, or `'none'`. */
|
|
35
|
+
trace_id: string;
|
|
36
|
+
session_id: string;
|
|
37
|
+
task_id?: string;
|
|
38
|
+
phase?: string;
|
|
39
|
+
agent: string;
|
|
40
|
+
items: ReceiptItem[];
|
|
41
|
+
/** True when the receipt asserts nothing relevant was surfaced. */
|
|
42
|
+
no_relevant_knowledge: boolean;
|
|
43
|
+
}
|
|
44
|
+
export type ReceiptRejectReason = 'trace_not_found' | 'id_not_in_trace' | 'wrong_session' | 'expired' | 'duplicate_conflicting_terminal' | 'invalid_outcome' | 'empty_receipt';
|
|
45
|
+
export type ReceiptValidationResult = {
|
|
46
|
+
ok: true;
|
|
47
|
+
/** Items that should be freshly emitted (excludes idempotent skips). */
|
|
48
|
+
accepted: ReceiptItem[];
|
|
49
|
+
/** Items already recorded with the same outcome — skip emitting. */
|
|
50
|
+
idempotent_skips: ReceiptItem[];
|
|
51
|
+
/** The matched retrieval trace, or null for the real-empty (`'none'`) path. */
|
|
52
|
+
trace: RetrievedEvent | null;
|
|
53
|
+
/** True when this receipt closes the loop with a `no_relevant` terminal. */
|
|
54
|
+
closes_no_relevant: boolean;
|
|
55
|
+
/**
|
|
56
|
+
* Per-item rejections when SOME items were accepted but others were not
|
|
57
|
+
* (id_not_in_trace / conflicting). Present only when non-empty.
|
|
58
|
+
*/
|
|
59
|
+
rejected_items?: Array<{
|
|
60
|
+
item: ReceiptItem;
|
|
61
|
+
reason: ReceiptRejectReason;
|
|
62
|
+
}>;
|
|
63
|
+
} | {
|
|
64
|
+
ok: false;
|
|
65
|
+
rejected: true;
|
|
66
|
+
reason: ReceiptRejectReason;
|
|
67
|
+
detail: string;
|
|
68
|
+
/** Items rejected by per-item checks (id_not_in_trace / conflicting). */
|
|
69
|
+
rejected_items?: Array<{
|
|
70
|
+
item: ReceiptItem;
|
|
71
|
+
reason: ReceiptRejectReason;
|
|
72
|
+
}>;
|
|
73
|
+
};
|
|
74
|
+
/**
|
|
75
|
+
* Receipt validity window. A receipt must be filed within this many
|
|
76
|
+
* milliseconds of the retrieval trace's timestamp. Generous constant (30 min)
|
|
77
|
+
* covers slow agents. NOTE: this is a compile-time constant, NOT configurable
|
|
78
|
+
* via the config schema — raise an issue if runtime configurability is needed.
|
|
79
|
+
*/
|
|
80
|
+
export declare const RECEIPT_VALIDITY_MS: number;
|
|
81
|
+
/** The `trace_id` sentinel meaning "no retrieval occurred". */
|
|
82
|
+
export declare const NO_TRACE_SENTINEL = "none";
|
|
83
|
+
/**
|
|
84
|
+
* Validate a receipt against the authoritative event log. Never throws — any
|
|
85
|
+
* internal error fails open by accepting the items (the agent's work must not
|
|
86
|
+
* be blocked by a validator crash). Rejections are AUDITED by the caller via
|
|
87
|
+
* the returned reason; the validator itself does not write audit events to
|
|
88
|
+
* keep it side-effect-free and testable.
|
|
89
|
+
*/
|
|
90
|
+
export declare function validateReceipt(ctx: ReceiptValidationContext): Promise<ReceiptValidationResult>;
|
|
91
|
+
declare function findTrace(events: KnowledgeEvent[], traceId: string): RetrievedEvent | null;
|
|
92
|
+
declare function isTerminalReceipt(e: KnowledgeEvent): boolean;
|
|
93
|
+
export declare const _internals: {
|
|
94
|
+
findTrace: typeof findTrace;
|
|
95
|
+
isTerminalReceipt: typeof isTerminalReceipt;
|
|
96
|
+
VALID_OUTCOMES: ReadonlySet<string>;
|
|
97
|
+
};
|
|
98
|
+
export {};
|
|
@@ -80,6 +80,9 @@ export interface MicroReflectorInput {
|
|
|
80
80
|
tool: unknown;
|
|
81
81
|
args?: unknown;
|
|
82
82
|
sessionID?: unknown;
|
|
83
|
+
/** (#1849) callID from the SDK tool.execute.after input — used to recover the
|
|
84
|
+
* snapshot args (the SDK toolAfter input has NO args field). */
|
|
85
|
+
callID?: unknown;
|
|
83
86
|
}
|
|
84
87
|
export interface MicroReflectorOutput {
|
|
85
88
|
output?: unknown;
|
|
@@ -23,6 +23,9 @@ export interface PrAutoSubscribeHook {
|
|
|
23
23
|
tool: string;
|
|
24
24
|
sessionID?: string;
|
|
25
25
|
args?: unknown;
|
|
26
|
+
/** (#1849) SDK tool.execute.after input carries callID (not args); used
|
|
27
|
+
* to recover the snapshot args via resolveToolAfterContext. */
|
|
28
|
+
callID?: string;
|
|
26
29
|
}, output: {
|
|
27
30
|
output?: unknown;
|
|
28
31
|
args?: unknown;
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Promotion-evidence store (issue #1849 §B2).
|
|
3
|
+
*
|
|
4
|
+
* Append-only, FIFO-bounded JSONL store for {@link PromotionEvidenceRecord}s
|
|
5
|
+
* produced when a validated terminal receipt (applied/violated/contradicted) is
|
|
6
|
+
* filed. This is the wiring that finally feeds #1847's
|
|
7
|
+
* {@link evaluatePromotionPolicy} consumer (previously inert "until #1849
|
|
8
|
+
* produces real receipts").
|
|
9
|
+
*
|
|
10
|
+
* Per-worktree by design: promotion evidence records THIS worktree's observed
|
|
11
|
+
* applications. It is intentionally NOT a member of `KNOWLEDGE_FAMILY` (the
|
|
12
|
+
* linked-cohort shared-artifact manifest), matching the precedent set by
|
|
13
|
+
* `src/turbo/epic/promotion-evidence.ts`. It lives under the project-root
|
|
14
|
+
* `.swarm/` (via {@link validateSwarmPath}), NOT the link-aware shared store
|
|
15
|
+
* dir, so it stays per-worktree.
|
|
16
|
+
*/
|
|
17
|
+
import type { PromotionEvidenceRecord } from './knowledge-types.js';
|
|
18
|
+
/** Resolve the promotion-evidence log path under the project-root `.swarm/`. */
|
|
19
|
+
export declare function resolvePromotionEvidencePath(directory: string): string;
|
|
20
|
+
/**
|
|
21
|
+
* Append validated promotion-evidence records. Fail-open + bounded: a write
|
|
22
|
+
* error logs and continues (the receipt event itself is the authoritative
|
|
23
|
+
* record; promotion evidence is a derived consumer). FIFO-trims the log when it
|
|
24
|
+
* exceeds {@link MAX_PROMOTION_EVIDENCE_ENTRIES}.
|
|
25
|
+
*/
|
|
26
|
+
export declare function appendPromotionEvidence(directory: string, records: PromotionEvidenceRecord[]): Promise<void>;
|
|
27
|
+
/**
|
|
28
|
+
* Load all promotion-evidence records, grouped by entry_id. This is the loader
|
|
29
|
+
* that replaces the inert stub at `hive-promoter.ts:loadPromotionEvidence`.
|
|
30
|
+
* Returns an empty object when the file is absent (no evidence yet — the
|
|
31
|
+
* conservative default). Never throws.
|
|
32
|
+
*/
|
|
33
|
+
export declare function loadPromotionEvidenceByEntry(directory: string): Promise<Record<string, PromotionEvidenceRecord[]>>;
|
|
@@ -5,9 +5,12 @@
|
|
|
5
5
|
* NOT as session crash. Verified from guardrails.ts multiple existing throw sites.
|
|
6
6
|
* Safe blocking pattern: throw new Error(`SCOPE VIOLATION: ...`)
|
|
7
7
|
*
|
|
8
|
-
* Fires BEFORE write/edit tools execute. When a
|
|
9
|
-
*
|
|
8
|
+
* Fires BEFORE write/edit tools execute. When a coder attempts to modify a file
|
|
9
|
+
* outside its Task-correlated scope, blocks the call and injects an advisory.
|
|
10
10
|
*/
|
|
11
|
+
import { resolveAuthorizedScopeBinding, resolveAuthorizedScopeBindingForSession } from '../scope/scope-persistence';
|
|
12
|
+
import { type AgentSessionState } from '../state';
|
|
13
|
+
import { resolveWriteTargets } from './write-target-resolver';
|
|
11
14
|
/**
|
|
12
15
|
* Configuration for scope guard behavior.
|
|
13
16
|
*/
|
|
@@ -63,5 +66,9 @@ declare function sanitizePath(raw: string): string;
|
|
|
63
66
|
*/
|
|
64
67
|
export declare const _internals: {
|
|
65
68
|
sanitizePath: typeof sanitizePath;
|
|
69
|
+
resolveWriteTargets: typeof resolveWriteTargets;
|
|
70
|
+
resolveAuthorizedScopeBinding: typeof resolveAuthorizedScopeBinding;
|
|
71
|
+
resolveAuthorizedScopeBindingForSession: typeof resolveAuthorizedScopeBindingForSession;
|
|
72
|
+
resolveTaskId: (session: AgentSessionState | undefined) => string | null;
|
|
66
73
|
};
|
|
67
74
|
export {};
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
export declare const MAX_PATCH_FIELD_BYTES = 1000000;
|
|
2
|
+
export declare const MAX_PATCH_AGGREGATE_BYTES = 2000000;
|
|
3
|
+
export type WriteTargetResolution = {
|
|
4
|
+
status: 'resolved';
|
|
5
|
+
paths: string[];
|
|
6
|
+
} | {
|
|
7
|
+
status: 'unverifiable';
|
|
8
|
+
reason: string;
|
|
9
|
+
};
|
|
10
|
+
export interface WriteTargetResolverContext {
|
|
11
|
+
directory: string;
|
|
12
|
+
}
|
|
13
|
+
declare function genericResolver(args: Record<string, unknown>): WriteTargetResolution;
|
|
14
|
+
declare function extractResolver(args: Record<string, unknown>, context: WriteTargetResolverContext): WriteTargetResolution;
|
|
15
|
+
/** One authoritative resolver per registered write tool. */
|
|
16
|
+
export declare const WRITE_TARGET_RESOLVERS: {
|
|
17
|
+
write: typeof genericResolver;
|
|
18
|
+
edit: typeof genericResolver;
|
|
19
|
+
patch: (args: Record<string, unknown>, context: WriteTargetResolverContext) => WriteTargetResolution;
|
|
20
|
+
apply_patch: (args: Record<string, unknown>, context: WriteTargetResolverContext) => WriteTargetResolution;
|
|
21
|
+
swarm_apply_patch: (args: Record<string, unknown>, context: WriteTargetResolverContext) => WriteTargetResolution;
|
|
22
|
+
create_file: typeof genericResolver;
|
|
23
|
+
insert: typeof genericResolver;
|
|
24
|
+
replace: typeof genericResolver;
|
|
25
|
+
append: typeof genericResolver;
|
|
26
|
+
prepend: typeof genericResolver;
|
|
27
|
+
extract_code_blocks: typeof extractResolver;
|
|
28
|
+
};
|
|
29
|
+
export declare function resolveWriteTargets(toolName: string, args: unknown, context: WriteTargetResolverContext): WriteTargetResolution;
|
|
30
|
+
export {};
|