opencode-swarm 7.144.8 → 7.145.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/background/workspace-snapshot.d.ts +29 -0
- package/dist/cli/{config-doctor-zbqfp0v6.js → config-doctor-96jmxr7s.js} +3 -3
- package/dist/cli/{core-pz9gwatq.js → core-w78pc1hh.js} +3 -3
- package/dist/cli/{curation-policy-a511r0qz.js → curation-policy-smyc2mrm.js} +7 -7
- package/dist/cli/{curator-sk0dyvke.js → curator-59hzdxrv.js} +33 -32
- package/dist/cli/{curator-drift-ckjm272w.js → curator-drift-r50x1rac.js} +4 -4
- package/dist/cli/{curator-llm-factory-3nq3p02z.js → curator-llm-factory-g794pv51.js} +33 -32
- package/dist/cli/dispatch-ndxbsk98.js +1 -1
- package/dist/cli/{evidence-summary-service-abwrjqd0.js → evidence-summary-service-41m0cna6.js} +15 -14
- package/dist/cli/{gate-evidence-aa7vvtcd.js → gate-evidence-7aywx7qa.js} +10 -9
- package/dist/cli/guardrail-explain-j88dhm6w.js +65 -0
- package/dist/cli/{guardrail-log-jw5mzs0d.js → guardrail-log-xcb3ke8s.js} +5 -5
- package/dist/cli/{hive-promoter-m20j63yg.js → hive-promoter-nnnx5692.js} +33 -32
- package/dist/cli/{index-7qb0hn8n.js → index-17e73wac.js} +1 -1
- package/dist/cli/{index-r2rkwvzq.js → index-19v4tccw.js} +2 -2
- package/dist/cli/{index-vdha477y.js → index-2qrd8mfa.js} +1 -1
- package/dist/cli/{index-6z5jtf7d.js → index-34tawmyx.js} +4 -4
- package/dist/cli/{index-jdxnzbah.js → index-41t3hgaa.js} +10 -10
- package/dist/cli/index-4evasm2b.js +514 -0
- package/dist/cli/{index-gfvkttvd.js → index-7axx11dt.js} +1 -1
- package/dist/cli/{index-8dbzaf0m.js → index-8ef23wex.js} +4 -4
- package/dist/cli/{index-k7fk9fjs.js → index-90w06fqr.js} +107 -29
- package/dist/cli/{index-t2ntgzts.js → index-b7ntt9cw.js} +3 -3
- package/dist/cli/{index-c2rpht77.js → index-bst6epnr.js} +2703 -2054
- package/dist/cli/{index-tffg4mwr.js → index-cqfp05jb.js} +3 -3
- package/dist/cli/{index-1jsmmx7y.js → index-dppzthm9.js} +92 -35
- package/dist/cli/{index-h1p08s3n.js → index-dzan8czb.js} +1 -1
- package/dist/cli/{index-cwtpqm5f.js → index-e1pxav9g.js} +1 -1
- package/dist/cli/{index-d1dbpxxk.js → index-evpgszmp.js} +2 -2
- package/dist/cli/{index-cx51wy0c.js → index-ff66fbjt.js} +10 -10
- package/dist/cli/{index-wknz5c8q.js → index-fwnhh6s7.js} +2 -2
- package/dist/cli/{index-hkdgkkhb.js → index-gey2257h.js} +2 -2
- package/dist/cli/{index-f9vvg5xb.js → index-gf03198s.js} +67 -2
- package/dist/cli/{index-z4fssj97.js → index-kxzgnz2h.js} +20 -20
- package/dist/cli/{index-9s8drsf9.js → index-mpf01swm.js} +4 -21
- package/dist/cli/{index-sxe5nyq4.js → index-mrkgxfeh.js} +13 -15
- package/dist/cli/{index-0v1f2sdb.js → index-neh8azwc.js} +2 -2
- package/dist/cli/{index-3k3nbs52.js → index-qpke2x5h.js} +9 -9
- package/dist/cli/{index-n4hwcsbd.js → index-rtkttser.js} +5 -5
- package/dist/cli/{index-xx8tm58n.js → index-sfemjcb8.js} +5 -5
- package/dist/cli/{index-bv44950t.js → index-tm0bezd9.js} +1 -1
- package/dist/cli/{index-r14qx363.js → index-tw8ck794.js} +1 -1
- package/dist/cli/{index-t72g4a7y.js → index-xz4x17z0.js} +35 -34
- package/dist/cli/{index-nmy6rss1.js → index-ymyke19q.js} +1 -1
- package/dist/cli/{index-f36ybbsv.js → index-z9yhhk6q.js} +93 -5
- package/dist/cli/{index-xp5g9eps.js → index-zpp507z0.js} +15 -1
- package/dist/cli/index.js +33 -32
- package/dist/cli/{knowledge-escalator-mg8qb7tm.js → knowledge-escalator-s6acdpwj.js} +15 -14
- package/dist/cli/{knowledge-events-3zxf8xpb.js → knowledge-events-jprkz49t.js} +13 -12
- package/dist/cli/{knowledge-link-4cg4776a.js → knowledge-link-zvtmj756.js} +6 -6
- package/dist/cli/{knowledge-store-awnm8s6c.js → knowledge-store-mc4awds4.js} +7 -7
- package/dist/cli/{knowledge-validator-3ke5scx3.js → knowledge-validator-pe4ncrvj.js} +9 -9
- package/dist/cli/model-preflight-77dwxfv5.js +170 -0
- package/dist/cli/{pending-delegations-9h1jmtw1.js → pending-delegations-epzht3d7.js} +6 -6
- package/dist/cli/{pr-subscriptions-8pg34pev.js → pr-subscriptions-2ahy8g87.js} +6 -6
- package/dist/cli/{runner-cqecp1na.js → runner-ra9pjhp2.js} +8 -7
- package/dist/cli/{scan-cursor-00rbxkb4.js → scan-cursor-hdzhqwzj.js} +8 -8
- package/dist/cli/{schema-5nmkp1pc.js → schema-pg85z06v.js} +1 -1
- package/dist/cli/{scope-persistence-6m79atw9.js → scope-persistence-v8we8ja7.js} +11 -7
- package/dist/cli/{skill-generator-gv70s796.js → skill-generator-ctskfct2.js} +17 -16
- package/dist/cli/{telemetry-cybx6cfz.js → telemetry-c21dgffc.js} +1 -1
- package/dist/cli/{workspace-snapshot-d89zm6wm.js → workspace-snapshot-kznz5e13.js} +3 -1
- package/dist/cli/{worktree-collision-ownership-vy0kxa98.js → worktree-collision-ownership-f7se4wbf.js} +10 -10
- package/dist/cli/{worktree-isolation-bne0p54w.js → worktree-isolation-j4qb7mgb.js} +35 -32
- package/dist/cli/{worktree-provisioning-owner-zzkjycp1.js → worktree-provisioning-owner-72cyddz5.js} +3 -3
- package/dist/commands/close.d.ts +8 -1
- package/dist/config/evidence-schema.d.ts +6 -6
- package/dist/config/plan-schema.d.ts +2 -2
- package/dist/config/schema.d.ts +7 -7
- package/dist/evidence/task-file.d.ts +16 -16
- package/dist/hooks/delegation-gate/worktree-isolation.d.ts +4 -0
- package/dist/index.js +603 -559
- package/dist/memory/schema.d.ts +3 -3
- package/dist/observability/catalog.d.ts +5 -4
- package/dist/observability/envelope.d.ts +2 -2
- package/dist/scope/scope-binding.d.ts +16 -0
- package/dist/services/model-preflight.d.ts +151 -0
- package/dist/services/session-reflection.d.ts +24 -0
- package/dist/services/swarm-residue.d.ts +151 -0
- package/dist/telemetry.d.ts +32 -2
- package/dist/tools/knowledge-receipt.d.ts +1 -1
- package/dist/tools/placeholder-scan.d.ts +64 -0
- package/dist/tools/sast-scan.d.ts +6 -0
- package/dist/utils/atomic-write.d.ts +185 -0
- package/package.json +1 -1
- package/dist/cli/guardrail-explain-hvtyr2fz.js +0 -64
- package/dist/cli/{index-fv0s19g9.js → index-w8pgjr75.js} +3 -3
package/dist/memory/schema.d.ts
CHANGED
|
@@ -48,8 +48,8 @@ export declare const MemoryKindSchema: z.ZodEnum<{
|
|
|
48
48
|
}>;
|
|
49
49
|
export declare const MemorySourceSchema: z.ZodObject<{
|
|
50
50
|
type: z.ZodEnum<{
|
|
51
|
-
file: "file";
|
|
52
51
|
agent: "agent";
|
|
52
|
+
file: "file";
|
|
53
53
|
tool: "tool";
|
|
54
54
|
manual: "manual";
|
|
55
55
|
test: "test";
|
|
@@ -113,8 +113,8 @@ export declare const MemoryRecordSchema: z.ZodObject<{
|
|
|
113
113
|
}>;
|
|
114
114
|
source: z.ZodObject<{
|
|
115
115
|
type: z.ZodEnum<{
|
|
116
|
-
file: "file";
|
|
117
116
|
agent: "agent";
|
|
117
|
+
file: "file";
|
|
118
118
|
tool: "tool";
|
|
119
119
|
manual: "manual";
|
|
120
120
|
test: "test";
|
|
@@ -203,8 +203,8 @@ export declare const MemoryProposalSchema: z.ZodObject<{
|
|
|
203
203
|
}>;
|
|
204
204
|
source: z.ZodObject<{
|
|
205
205
|
type: z.ZodEnum<{
|
|
206
|
-
file: "file";
|
|
207
206
|
agent: "agent";
|
|
207
|
+
file: "file";
|
|
208
208
|
tool: "tool";
|
|
209
209
|
manual: "manual";
|
|
210
210
|
test: "test";
|
|
@@ -1,15 +1,16 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* The event catalog (issue #2029).
|
|
3
3
|
*
|
|
4
|
-
* Exactly
|
|
4
|
+
* Exactly 45 entries, matching the `TelemetryEvent` union at
|
|
5
5
|
* `src/telemetry.ts:15-92`. Thirty-eight predate the #2029 contract; the 39th is
|
|
6
6
|
* `agent_conflict_detected` (previously emitted through a force-cast past the
|
|
7
7
|
* type system), the 40th is `close_archive_result` (issue #2030 — the
|
|
8
8
|
* structured close/archive result event), the 41st is the bounded diagnostic
|
|
9
9
|
* projection of authoritative knowledge-receipt transitions (issue #2031).
|
|
10
10
|
* The 42nd is the human-only `knowledge_maintenance` quarantine audit
|
|
11
|
-
* (issue #2033),
|
|
12
|
-
* mutation audit
|
|
11
|
+
* (issue #2033), the 43rd is the aggregate `context_pruned` transcript
|
|
12
|
+
* mutation audit, and the 44th is the bounded `residue_health` atomic-write
|
|
13
|
+
* residue audit (issue #2035). These late additions are instances of
|
|
13
14
|
* the defect class this contract exists to close: an event kind entering the
|
|
14
15
|
* stream with no registration.
|
|
15
16
|
*
|
|
@@ -64,7 +65,7 @@ export interface CatalogEntry {
|
|
|
64
65
|
/**
|
|
65
66
|
* Whether an event of this kind must carry `trace.parentSpanId`.
|
|
66
67
|
*
|
|
67
|
-
* `false` for all
|
|
68
|
+
* `false` for all 45 entries today, and that is a truthful statement about
|
|
68
69
|
* the current system rather than a placeholder: no producer supplies a
|
|
69
70
|
* parent span, so `createObservation` never sets one. Setting this to `true`
|
|
70
71
|
* for a kind whose producer cannot supply a parent would make every
|
|
@@ -38,11 +38,11 @@ export declare const EventCategorySchema: z.ZodEnum<{
|
|
|
38
38
|
export type EventCategory = z.infer<typeof EventCategorySchema>;
|
|
39
39
|
/** Syslog-shaped severity ladder. */
|
|
40
40
|
export declare const EventSeveritySchema: z.ZodEnum<{
|
|
41
|
-
error: "error";
|
|
42
41
|
debug: "debug";
|
|
43
42
|
info: "info";
|
|
44
43
|
notice: "notice";
|
|
45
44
|
warning: "warning";
|
|
45
|
+
error: "error";
|
|
46
46
|
critical: "critical";
|
|
47
47
|
}>;
|
|
48
48
|
export type EventSeverity = z.infer<typeof EventSeveritySchema>;
|
|
@@ -297,11 +297,11 @@ export declare const ObservabilityEventSchema: z.ZodObject<{
|
|
|
297
297
|
unrecognized: "unrecognized";
|
|
298
298
|
}>;
|
|
299
299
|
severity: z.ZodEnum<{
|
|
300
|
-
error: "error";
|
|
301
300
|
debug: "debug";
|
|
302
301
|
info: "info";
|
|
303
302
|
notice: "notice";
|
|
304
303
|
warning: "warning";
|
|
304
|
+
error: "error";
|
|
305
305
|
critical: "critical";
|
|
306
306
|
}>;
|
|
307
307
|
occurredAt: z.ZodString;
|
|
@@ -198,6 +198,22 @@ export declare function clearExactScopeBinding(input: {
|
|
|
198
198
|
}): ScopeBinding | null;
|
|
199
199
|
export declare function installScopeBindingTombstone(binding: ScopeBinding): void;
|
|
200
200
|
export declare function hasScopeBindingDenyOverlay(binding: ScopeBinding): boolean;
|
|
201
|
+
/**
|
|
202
|
+
* Issue #2271 bug 5: deny check that ignores purely time-based (sweep)
|
|
203
|
+
* tombstones. `sweepExpired` installs an 'expired'-lifecycle tombstone at
|
|
204
|
+
* revision+1 for every lapsed generation on ANY scope read — that is not a
|
|
205
|
+
* deliberate denial, and the durable CAS in the idle-revival path re-verifies
|
|
206
|
+
* the on-disk generation anyway. Deliberate revocation classes
|
|
207
|
+
* ('revoked'/'superseded') and any failed-revocation overlay still deny.
|
|
208
|
+
*/
|
|
209
|
+
export declare function hasDeliberateScopeBindingDenyOverlay(binding: ScopeBinding): boolean;
|
|
210
|
+
/**
|
|
211
|
+
* Issue #2271 bug 5: remove a sweep-signature tombstone so a durable-CAS
|
|
212
|
+
* revival can be admitted in memory. Only 'expired'-lifecycle tombstones at
|
|
213
|
+
* or below the revived revision are cleared — deliberate revocations and any
|
|
214
|
+
* newer overlay are preserved.
|
|
215
|
+
*/
|
|
216
|
+
export declare function clearSweepTombstoneForRevival(binding: ScopeBinding): void;
|
|
201
217
|
/** Fail-closed overlay used only when durable revocation cannot be verified. */
|
|
202
218
|
export declare function installFailedRevocationOverlay(binding: ScopeBinding, reason: Exclude<ScopeBindingLifecycleState, 'live'>): boolean;
|
|
203
219
|
/**
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Agent model-resolution preflight (issue #2271 bug 4).
|
|
3
|
+
*
|
|
4
|
+
* Agent model strings (DEFAULT_MODELS plus user `agents.<role>.model`
|
|
5
|
+
* overrides) are handed to the OpenCode host unvalidated. When one does not
|
|
6
|
+
* resolve ("Model not found", "Forbidden"), dispatch-lanes classifies the
|
|
7
|
+
* failure as permanent, the affected agent never runs, and the plan-critic
|
|
8
|
+
* gate wedges into manual `approve_plan_critic` overrides because no APPROVED
|
|
9
|
+
* verdict is ever produced.
|
|
10
|
+
*
|
|
11
|
+
* This module validates configured model IDs against the live provider
|
|
12
|
+
* catalog (`client.provider.list()`). Every check is FAIL-OPEN: if the catalog
|
|
13
|
+
* is unreachable or malformed, results come back `unknown` and callers must
|
|
14
|
+
* proceed — the preflight only acts on a POSITIVE confirmation that a model
|
|
15
|
+
* does not resolve.
|
|
16
|
+
*/
|
|
17
|
+
import type { OpencodeClient } from '@opencode-ai/sdk';
|
|
18
|
+
import type { PluginConfig } from '../config/schema.js';
|
|
19
|
+
/** Tight bound for the catalog HTTP call — it runs on init/doctor paths. */
|
|
20
|
+
export declare const PROVIDER_LIST_TIMEOUT_MS = 2000;
|
|
21
|
+
export interface ConfiguredAgentModel {
|
|
22
|
+
/** Agent role the model is configured for. */
|
|
23
|
+
agent: string;
|
|
24
|
+
/** Full model id in `provider/model` form. */
|
|
25
|
+
model: string;
|
|
26
|
+
/** Where the value came from. */
|
|
27
|
+
source: 'default' | 'override' | 'fallback';
|
|
28
|
+
}
|
|
29
|
+
export type ModelResolutionStatus = 'ok' | 'unresolved' | 'unknown';
|
|
30
|
+
export interface ModelResolution {
|
|
31
|
+
agent: string;
|
|
32
|
+
model: string;
|
|
33
|
+
source: ConfiguredAgentModel['source'];
|
|
34
|
+
status: ModelResolutionStatus;
|
|
35
|
+
/** Human-readable explanation for non-ok statuses. */
|
|
36
|
+
detail?: string;
|
|
37
|
+
}
|
|
38
|
+
export interface ModelPreflightResult {
|
|
39
|
+
/** False when the catalog could not be fetched — every entry is `unknown`. */
|
|
40
|
+
catalogAvailable: boolean;
|
|
41
|
+
resolutions: ModelResolution[];
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Split a model id into its provider and model parts. Returns null for ids
|
|
45
|
+
* without a provider prefix (e.g. a bare model name) — those cannot be
|
|
46
|
+
* validated against a provider catalog.
|
|
47
|
+
*/
|
|
48
|
+
export declare function splitModelId(model: string): {
|
|
49
|
+
provider: string;
|
|
50
|
+
model: string;
|
|
51
|
+
} | null;
|
|
52
|
+
/**
|
|
53
|
+
* Collect every model id the swarm could dispatch with: DEFAULT_MODELS
|
|
54
|
+
* entries, user agent overrides, and declared fallback_models. Overriding one
|
|
55
|
+
* role replaces its default (mirrors getModelForAgent precedence).
|
|
56
|
+
*/
|
|
57
|
+
export declare function collectConfiguredAgentModels(config?: PluginConfig): ConfiguredAgentModel[];
|
|
58
|
+
/** Provider catalog snapshot: provider id → set of model ids. */
|
|
59
|
+
export type ProviderCatalog = Map<string, Set<string>>;
|
|
60
|
+
/** Test/gate seam: drop the cached catalogs (used after config changes and denials). */
|
|
61
|
+
export declare function invalidateProviderCatalogCache(): void;
|
|
62
|
+
/**
|
|
63
|
+
* Fetch the provider catalog. Returns null when the catalog cannot be
|
|
64
|
+
* obtained or parsed — callers fail open on null.
|
|
65
|
+
*/
|
|
66
|
+
export declare function fetchProviderCatalog(client: OpencodeClient | null): Promise<ProviderCatalog | null>;
|
|
67
|
+
/**
|
|
68
|
+
* Validate collected models against a catalog. A model whose provider is
|
|
69
|
+
* absent from the catalog, or whose provider exists but does not list the
|
|
70
|
+
* model, is `unresolved` — but only when the catalog itself was successfully
|
|
71
|
+
* fetched (callers must treat a null catalog as fail-open, never unresolved).
|
|
72
|
+
*/
|
|
73
|
+
export declare function resolveAgainstCatalog(models: ConfiguredAgentModel[], catalog: ProviderCatalog | null): ModelPreflightResult;
|
|
74
|
+
/**
|
|
75
|
+
* End-to-end preflight: collect configured models, fetch the catalog, and
|
|
76
|
+
* resolve. Fail-open on every catalog error.
|
|
77
|
+
*/
|
|
78
|
+
export declare function runModelPreflight(config: PluginConfig | undefined, client: OpencodeClient | null): Promise<ModelPreflightResult>;
|
|
79
|
+
/**
|
|
80
|
+
* Resolves a single model id against the live catalog for gate preflights.
|
|
81
|
+
* Returns 'unknown' whenever the catalog cannot be fetched — gates must only
|
|
82
|
+
* block on 'unresolved'.
|
|
83
|
+
*/
|
|
84
|
+
export declare function checkSingleModelResolution(model: string, client: OpencodeClient | null): Promise<ModelResolutionStatus>;
|
|
85
|
+
export declare const _internals: {
|
|
86
|
+
/** Injectable seam for the SDK catalog call (tests substitute this). */
|
|
87
|
+
providerList: (client: OpencodeClient) => Promise<({
|
|
88
|
+
data: undefined;
|
|
89
|
+
error: unknown;
|
|
90
|
+
} | {
|
|
91
|
+
data: {
|
|
92
|
+
all: Array<{
|
|
93
|
+
api?: string;
|
|
94
|
+
name: string;
|
|
95
|
+
env: Array<string>;
|
|
96
|
+
id: string;
|
|
97
|
+
npm?: string;
|
|
98
|
+
models: {
|
|
99
|
+
[key: string]: {
|
|
100
|
+
id: string;
|
|
101
|
+
name: string;
|
|
102
|
+
release_date: string;
|
|
103
|
+
attachment: boolean;
|
|
104
|
+
reasoning: boolean;
|
|
105
|
+
temperature: boolean;
|
|
106
|
+
tool_call: boolean;
|
|
107
|
+
cost?: {
|
|
108
|
+
input: number;
|
|
109
|
+
output: number;
|
|
110
|
+
cache_read?: number;
|
|
111
|
+
cache_write?: number;
|
|
112
|
+
context_over_200k?: {
|
|
113
|
+
input: number;
|
|
114
|
+
output: number;
|
|
115
|
+
cache_read?: number;
|
|
116
|
+
cache_write?: number;
|
|
117
|
+
};
|
|
118
|
+
};
|
|
119
|
+
limit: {
|
|
120
|
+
context: number;
|
|
121
|
+
output: number;
|
|
122
|
+
};
|
|
123
|
+
modalities?: {
|
|
124
|
+
input: Array<"text" | "audio" | "image" | "video" | "pdf">;
|
|
125
|
+
output: Array<"text" | "audio" | "image" | "video" | "pdf">;
|
|
126
|
+
};
|
|
127
|
+
experimental?: boolean;
|
|
128
|
+
status?: "alpha" | "beta" | "deprecated" | "active";
|
|
129
|
+
options: {
|
|
130
|
+
[key: string]: unknown;
|
|
131
|
+
};
|
|
132
|
+
headers?: {
|
|
133
|
+
[key: string]: string;
|
|
134
|
+
};
|
|
135
|
+
provider?: {
|
|
136
|
+
npm: string;
|
|
137
|
+
};
|
|
138
|
+
};
|
|
139
|
+
};
|
|
140
|
+
}>;
|
|
141
|
+
default: {
|
|
142
|
+
[key: string]: string;
|
|
143
|
+
};
|
|
144
|
+
connected: Array<string>;
|
|
145
|
+
};
|
|
146
|
+
error: undefined;
|
|
147
|
+
}) & {
|
|
148
|
+
request: Request;
|
|
149
|
+
response: Response;
|
|
150
|
+
}>;
|
|
151
|
+
};
|
|
@@ -109,6 +109,14 @@ export interface SessionReflectionData {
|
|
|
109
109
|
knowledgeDelta?: KnowledgeDelta;
|
|
110
110
|
skillViolations: SkillViolationSignal[];
|
|
111
111
|
contradictionCandidates: ContradictionCandidate[];
|
|
112
|
+
/**
|
|
113
|
+
* Issue #2271 bug 6: rejection/circuit-breaker/manual-approval event counts
|
|
114
|
+
* by type, read from the session ledger (.swarm/events.jsonl). Gate denials
|
|
115
|
+
* throw in tool.execute.before and never increment ToolAggregate counters
|
|
116
|
+
* (denied calls do not fire toolAfter), so without this field a session
|
|
117
|
+
* full of gate rejections reports "0 tool failures or gate rejections".
|
|
118
|
+
*/
|
|
119
|
+
ledgerRejections?: Record<string, number>;
|
|
112
120
|
}
|
|
113
121
|
export interface SessionReflectionResult {
|
|
114
122
|
data: SessionReflectionData;
|
|
@@ -138,6 +146,21 @@ declare function gatherRetroLessonsAndTaxonomy(directory: string): Promise<{
|
|
|
138
146
|
taxonomy: Record<string, number>;
|
|
139
147
|
}>;
|
|
140
148
|
declare function gatherGateFailures(directory: string): Promise<GateFailureSummary[]>;
|
|
149
|
+
/**
|
|
150
|
+
* Count rejection-class events in the session ledger. Reads the LIVE
|
|
151
|
+
* .swarm/events.jsonl first (finalize runs before archive in the close
|
|
152
|
+
* pipeline), falling back to the newest archived copy for a partially-run
|
|
153
|
+
* prior close. Fail-open: any read/parse problem yields empty counts.
|
|
154
|
+
*
|
|
155
|
+
* When `sessionId` is provided, events carrying a DIFFERENT session id are
|
|
156
|
+
* ignored so a per-session close summary cannot overcount sibling sessions'
|
|
157
|
+
* rejections in multi-swarm projects. Events with NO session field are still
|
|
158
|
+
* counted: several rejection writers emit none (coder_retry_circuit_breaker,
|
|
159
|
+
* architect_loop_detected), a sessionless event cannot be attributed to a
|
|
160
|
+
* sibling session, and dropping them would resurrect the bug-6 undercount in
|
|
161
|
+
* the standard close flow.
|
|
162
|
+
*/
|
|
163
|
+
declare function gatherLedgerRejections(directory: string, sessionId?: string): Promise<Record<string, number>>;
|
|
141
164
|
/**
|
|
142
165
|
* Top skills by violation this session (issue #2077).
|
|
143
166
|
*
|
|
@@ -242,6 +265,7 @@ export declare const _internals: {
|
|
|
242
265
|
gatherAgentDispatches: typeof gatherAgentDispatches;
|
|
243
266
|
gatherRetroLessonsAndTaxonomy: typeof gatherRetroLessonsAndTaxonomy;
|
|
244
267
|
gatherGateFailures: typeof gatherGateFailures;
|
|
268
|
+
gatherLedgerRejections: typeof gatherLedgerRejections;
|
|
245
269
|
buildReflectionDataSummary: typeof buildReflectionDataSummary;
|
|
246
270
|
buildDeterministicReport: typeof buildDeterministicReport;
|
|
247
271
|
gatherSkillViolations: typeof gatherSkillViolations;
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared atomic-write residue surface (issue #2035): read-only inventory,
|
|
3
|
+
* gated recoverable quarantine, manifest-backed rollback, and the ONE
|
|
4
|
+
* formatter every reporting surface (close clean stage, close dry-run,
|
|
5
|
+
* config doctor, diagnose) renders from — so close and doctor report the
|
|
6
|
+
* same inventory from a shared implementation by construction.
|
|
7
|
+
*
|
|
8
|
+
* Safety contract (issue #2035 reqs 4-7):
|
|
9
|
+
* - The scanner never traverses outside the canonical project `.swarm/`
|
|
10
|
+
* root, never follows symlinks (Dirent + lstat only), never infers
|
|
11
|
+
* ownership from content, and never reads content except a bounded
|
|
12
|
+
* sha256 at quarantine time.
|
|
13
|
+
* - Quarantine MOVES (never deletes) only verified stale residue: exact
|
|
14
|
+
* registered-grammar match with an instance token, age ≥
|
|
15
|
+
* RESIDUE_STALE_AGE_MS, git-untracked, non-symlink, no active lock,
|
|
16
|
+
* size ≤ RESIDUE_HASH_MAX_BYTES, parsed target present, and unchanged
|
|
17
|
+
* (mtime+size) between scan and move (TOCTOU re-check — a lockless
|
|
18
|
+
* writer still filling its temp mutates these).
|
|
19
|
+
* - Everything else — recent, active, tracked, ambiguous, constant-name,
|
|
20
|
+
* malformed, unmatched, outside-root — is PRESERVED and reported.
|
|
21
|
+
* - Rollback is exact, manifest-verified, and idempotent.
|
|
22
|
+
*/
|
|
23
|
+
import { type SwarmTempGrammar } from '../utils/atomic-write';
|
|
24
|
+
/** Age gate: a temp older than this is "old". 30 min exceeds any legitimate
|
|
25
|
+
* single bounded write (≤256 MiB + AV/rename-retry adds seconds), while still
|
|
26
|
+
* catching session-old residue at close time. */
|
|
27
|
+
export declare const RESIDUE_STALE_AGE_MS: number;
|
|
28
|
+
/** Bounded scan: stop (and report `truncated`) beyond this many entries. */
|
|
29
|
+
export declare const MAX_RESIDUE_SCAN_ENTRIES = 20000;
|
|
30
|
+
/** Bounded scan depth below `.swarm/`. */
|
|
31
|
+
export declare const RESIDUE_SCAN_DEPTH = 8;
|
|
32
|
+
/** Hash/move bound per residue file. Larger candidates are reported only. */
|
|
33
|
+
export declare const RESIDUE_HASH_MAX_BYTES: number;
|
|
34
|
+
/** `.swarm/` immediate-child subtrees the scanner never descends into. */
|
|
35
|
+
export declare const RESIDUE_SKIP_DIRS: readonly string[];
|
|
36
|
+
export interface ResidueEntry {
|
|
37
|
+
/** Path relative to the `.swarm/` root (never absolute — no path leak). */
|
|
38
|
+
relPath: string;
|
|
39
|
+
grammarId: string;
|
|
40
|
+
grammarEra: SwarmTempGrammar['era'];
|
|
41
|
+
bytes: number;
|
|
42
|
+
mtimeMs: number;
|
|
43
|
+
ageMs: number;
|
|
44
|
+
isSymlink: boolean;
|
|
45
|
+
tracked: 'tracked' | 'untracked' | 'unknown';
|
|
46
|
+
lockHeld: boolean;
|
|
47
|
+
proposedAction: 'quarantine' | 'report_only';
|
|
48
|
+
reasons: readonly string[];
|
|
49
|
+
}
|
|
50
|
+
export interface ResidueInventorySummary {
|
|
51
|
+
matched: number;
|
|
52
|
+
eligible: number;
|
|
53
|
+
ambiguous: number;
|
|
54
|
+
totalBytes: number;
|
|
55
|
+
oldestAgeMs: number;
|
|
56
|
+
}
|
|
57
|
+
export interface ResidueInventory {
|
|
58
|
+
swarmRoot: string;
|
|
59
|
+
scannedEntries: number;
|
|
60
|
+
truncated: boolean;
|
|
61
|
+
/** Oldest first. Constant-name grammar hits are included only when stale. */
|
|
62
|
+
entries: readonly ResidueEntry[];
|
|
63
|
+
summary: ResidueInventorySummary;
|
|
64
|
+
gitState: 'ok' | 'unknown';
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Test seam (repo `_internals` convention — never mock.module). `now` drives
|
|
68
|
+
* age math; `queryTracked`/`activeLockTargets` isolate the git/lock signals.
|
|
69
|
+
*/
|
|
70
|
+
export declare const _internals: {
|
|
71
|
+
now: () => number;
|
|
72
|
+
/** Rename seam for the per-entry guarded move (PRR-005 regression tests). */
|
|
73
|
+
renameResidueEntry: (from: string, to: string) => void;
|
|
74
|
+
queryTracked: (projectRoot: string, swarmRoot: string) => {
|
|
75
|
+
tracked: Set<string> | undefined;
|
|
76
|
+
};
|
|
77
|
+
activeLockTargets: (directory: string) => Set<string>;
|
|
78
|
+
sha256File: (absPath: string) => string;
|
|
79
|
+
};
|
|
80
|
+
/** Read-only inventory of registered-grammar residue under `<directory>/.swarm`. */
|
|
81
|
+
export declare function inventorySwarmResidue(directory: string): Promise<ResidueInventory>;
|
|
82
|
+
export interface QuarantineManifestEntry {
|
|
83
|
+
original_rel_path: string;
|
|
84
|
+
stored_rel_path: string;
|
|
85
|
+
sha256: string;
|
|
86
|
+
bytes: number;
|
|
87
|
+
mtime_ms: number;
|
|
88
|
+
grammar_id: string;
|
|
89
|
+
reason: string;
|
|
90
|
+
}
|
|
91
|
+
export interface QuarantineManifest {
|
|
92
|
+
/**
|
|
93
|
+
* Manifest format version. Forward-compat POLICY (PR review PRR-009):
|
|
94
|
+
* rollback hard-rejects any version it does not know — a FUTURE schema
|
|
95
|
+
* bump MUST ship its own reader/migration before (or with) the writer,
|
|
96
|
+
* because payloads on disk are only recoverable through a manifest the
|
|
97
|
+
* current code can parse. Deliberate design: a partial-reader migration
|
|
98
|
+
* is more dangerous than a readable "unsupported manifest shape" error
|
|
99
|
+
* naming the version. Mixed-version operation is therefore unsafe by
|
|
100
|
+
* construction across schema bumps: downgrade with v2 batches present
|
|
101
|
+
* blocks rollback of those batches until the newer plugin returns.
|
|
102
|
+
*/
|
|
103
|
+
schema_version: 1;
|
|
104
|
+
batch_id: string;
|
|
105
|
+
created_at: string;
|
|
106
|
+
trigger: string;
|
|
107
|
+
entries: QuarantineManifestEntry[];
|
|
108
|
+
}
|
|
109
|
+
export interface QuarantineOutcomeItem {
|
|
110
|
+
relPath: string;
|
|
111
|
+
status: 'quarantined' | 'preserved';
|
|
112
|
+
reasons: readonly string[];
|
|
113
|
+
}
|
|
114
|
+
export interface QuarantineResult {
|
|
115
|
+
inventory: ResidueInventory;
|
|
116
|
+
/** Batch dir relative to `.swarm/` — undefined when nothing was moved. */
|
|
117
|
+
batchRelDir?: string;
|
|
118
|
+
quarantined: number;
|
|
119
|
+
/** report_only entries preserved at their original location. */
|
|
120
|
+
preserved: readonly QuarantineOutcomeItem[];
|
|
121
|
+
}
|
|
122
|
+
/**
|
|
123
|
+
* Quarantine verified stale residue (moves only — never deletes). Callers
|
|
124
|
+
* that can mutate pass an explicit trigger; `dryRun: true` returns the exact
|
|
125
|
+
* plan without touching the filesystem (preview/confirmation path).
|
|
126
|
+
*/
|
|
127
|
+
export declare function quarantineSwarmResidue(directory: string, options?: {
|
|
128
|
+
trigger?: string;
|
|
129
|
+
dryRun?: boolean;
|
|
130
|
+
}): Promise<QuarantineResult>;
|
|
131
|
+
export interface RollbackOutcomeItem {
|
|
132
|
+
relPath: string;
|
|
133
|
+
status: 'restored' | 'already-restored' | 'collision' | 'missing-copy';
|
|
134
|
+
}
|
|
135
|
+
export interface RollbackResult {
|
|
136
|
+
batchRelDir: string;
|
|
137
|
+
items: readonly RollbackOutcomeItem[];
|
|
138
|
+
/** True when every manifest entry resolved and the batch dir was removed. */
|
|
139
|
+
drained: boolean;
|
|
140
|
+
}
|
|
141
|
+
/**
|
|
142
|
+
* Roll back a quarantine batch (default: latest). Idempotent and
|
|
143
|
+
* order-independent across batches: an occupied original is compared by
|
|
144
|
+
* checksum — identical copies are dropped (already restored), differing
|
|
145
|
+
* content is left in place and reported as a collision, never overwritten.
|
|
146
|
+
*/
|
|
147
|
+
export declare function rollbackResidueQuarantine(directory: string, batchId?: string): Promise<RollbackResult>;
|
|
148
|
+
/** Bounded human rendering of an inventory (≤ maxEntries detail lines). */
|
|
149
|
+
export declare function formatResidueInventoryLines(inv: ResidueInventory, options?: {
|
|
150
|
+
maxEntries?: number;
|
|
151
|
+
}): string[];
|
package/dist/telemetry.d.ts
CHANGED
|
@@ -1,6 +1,12 @@
|
|
|
1
1
|
import { createObservation, toLegacyTelemetryLine } from './observability/index.js';
|
|
2
2
|
import type { DelegationCostFields } from './services/cost-accounting.js';
|
|
3
|
-
export type TelemetryEvent = 'session_started' | 'session_ended' | 'agent_activated' | 'delegation_begin' | 'delegation_end' | 'task_state_changed' | 'gate_passed' | 'gate_failed' | 'gate_parse_error' | 'reviewer_gate_decision' | 'phase_changed' | 'budget_updated' | 'context_pruned' | 'model_fallback'
|
|
3
|
+
export type TelemetryEvent = 'session_started' | 'session_ended' | 'agent_activated' | 'delegation_begin' | 'delegation_end' | 'task_state_changed' | 'gate_passed' | 'gate_failed' | 'gate_parse_error' | 'reviewer_gate_decision' | 'phase_changed' | 'budget_updated' | 'context_pruned' | 'model_fallback'
|
|
4
|
+
/**
|
|
5
|
+
* Issue #2271 bug 4 — a configured agent model id was POSITIVELY confirmed
|
|
6
|
+
* unresolvable against the live provider catalog (distinct from a runtime
|
|
7
|
+
* model_fallback: this fires at preflight, before any dispatch attempt).
|
|
8
|
+
*/
|
|
9
|
+
| 'model_unresolved' | 'hard_limit_hit' | 'revision_limit_hit' | 'loop_detected' | 'no_op_strong_warning' | 'scope_violation' | 'qa_skip_violation' | 'heartbeat' | 'turbo_mode_changed' | 'auto_oversight_escalation' | 'environment_detected' | 'evidence_lock_acquired' | 'evidence_lock_contended' | 'evidence_lock_stale_recovered' | 'plan_ledger_cas_retry' | 'plan_md_write_failed' | 'snapshot_failed' | 'gate_denial_loop'
|
|
4
10
|
/**
|
|
5
11
|
* Issue #2063 B5 — an ARMED execution episode reached the advisory rung:
|
|
6
12
|
* `execution_stall_warn_calls` tool calls with no delegation completion, no
|
|
@@ -26,7 +32,7 @@ export type TelemetryEvent = 'session_started' | 'session_ended' | 'agent_activa
|
|
|
26
32
|
* `prm_hard_stop` TRIGGER emitted by `src/prm/escalation.ts`. A trigger with
|
|
27
33
|
* no matching delivery means the containment never reached the agent.
|
|
28
34
|
*/
|
|
29
|
-
| 'prm_hard_stop_delivered' | 'agent_conflict_detected' | 'close_archive_result' | 'knowledge_receipt_transition' | 'knowledge_maintenance';
|
|
35
|
+
| 'prm_hard_stop_delivered' | 'agent_conflict_detected' | 'close_archive_result' | 'knowledge_receipt_transition' | 'knowledge_maintenance' | 'residue_health';
|
|
30
36
|
/** Stable classification for how a reviewer-gate decision was established. */
|
|
31
37
|
export type ReviewerGateEvidenceKind = 'genuine' | 'fallback' | 'data_quality' | 'block';
|
|
32
38
|
/**
|
|
@@ -133,6 +139,11 @@ export declare const telemetry: {
|
|
|
133
139
|
prunedTokensFreed: number;
|
|
134
140
|
}): void;
|
|
135
141
|
modelFallback(sessionId: string, agentName: string, fromModel: string, toModel: string, reason: string): void;
|
|
142
|
+
/**
|
|
143
|
+
* Issue #2271 bug 4 — preflight confirmed a configured model id does not
|
|
144
|
+
* resolve against the provider catalog. Emitted once per detected model.
|
|
145
|
+
*/
|
|
146
|
+
modelUnresolved(agentName: string, model: string, detail: string): void;
|
|
136
147
|
hardLimitHit(sessionId: string, agentName: string, limitType: string, value: number): void;
|
|
137
148
|
revisionLimitHit(sessionId: string, agentName: string): void;
|
|
138
149
|
loopDetected(sessionId: string, agentName: string, loopType: string): void;
|
|
@@ -206,6 +217,25 @@ export declare const telemetry: {
|
|
|
206
217
|
};
|
|
207
218
|
}>;
|
|
208
219
|
}): void;
|
|
220
|
+
/**
|
|
221
|
+
* Atomic-write residue health (issue #2035). Emitted after a residue
|
|
222
|
+
* quarantine run (close clean stage / doctor flag). Bounded payload:
|
|
223
|
+
* counts, one bounded age figure, total bytes, and per-grammar counts
|
|
224
|
+
* keyed by the frozen registry ids — never file names, paths, or content,
|
|
225
|
+
* enabling later reporting (PR 16/19) without leaking workspace layout.
|
|
226
|
+
*/
|
|
227
|
+
residueHealth(data: {
|
|
228
|
+
trigger: string;
|
|
229
|
+
scanned: number;
|
|
230
|
+
matched: number;
|
|
231
|
+
eligible: number;
|
|
232
|
+
ambiguous: number;
|
|
233
|
+
quarantined: number;
|
|
234
|
+
preserved: number;
|
|
235
|
+
total_bytes: number;
|
|
236
|
+
oldest_age_ms: number;
|
|
237
|
+
grammar_counts: Record<string, number>;
|
|
238
|
+
}): void;
|
|
209
239
|
/**
|
|
210
240
|
* Issue #2063 C2 — the PRM hard-stop DENIAL was actually delivered to the
|
|
211
241
|
* agent (thrown by the guardrails `toolBefore` consumer). `prm_hard_stop`
|
|
@@ -17,8 +17,8 @@ import { createSwarmTool } from './create-tool.js';
|
|
|
17
17
|
declare const ignoredItem: z.ZodObject<{
|
|
18
18
|
id: z.ZodString;
|
|
19
19
|
reason: z.ZodEnum<{
|
|
20
|
-
other: "other";
|
|
21
20
|
stale: "stale";
|
|
21
|
+
other: "other";
|
|
22
22
|
superseded: "superseded";
|
|
23
23
|
unsafe: "unsafe";
|
|
24
24
|
too_generic: "too_generic";
|
|
@@ -36,8 +36,72 @@ export interface PlaceholderScanResult {
|
|
|
36
36
|
files_with_findings: number;
|
|
37
37
|
};
|
|
38
38
|
}
|
|
39
|
+
/**
|
|
40
|
+
* Classify a single expression node as a "constant literal" for stub-skeleton
|
|
41
|
+
* detection. Returns true for nodes whose source text is one of:
|
|
42
|
+
* - `null`, `true`, `false` (JS/TS keywords; Python `none`/`True`/`False` differ)
|
|
43
|
+
* - `number` literals (e.g. `0`, `1`)
|
|
44
|
+
* - `string` literals (e.g. `""`)
|
|
45
|
+
* - `array` literals (e.g. `[]`)
|
|
46
|
+
* - `object` literals (e.g. `{}`)
|
|
47
|
+
* - `unary_expression` with operator `-` and number operand (e.g. `-1`)
|
|
48
|
+
* - `identifier` (a named constant reference, e.g. `CONFIG_DEFAULTS`)
|
|
49
|
+
* - `template_string` with NO `template_substitution` children
|
|
50
|
+
* (i.e. `\`hello\`` is constant; `\`hello ${world}\`` is not)
|
|
51
|
+
*
|
|
52
|
+
* Note: Python's `none`/`True`/`False`/`integer`/`float`/`string`/`list`/
|
|
53
|
+
* `dictionary`/`tuple` map to tree-sitter-python grammar node types and
|
|
54
|
+
* follow the same classification rules.
|
|
55
|
+
*/
|
|
56
|
+
declare function isConstantLiteralNode(node: any): boolean;
|
|
57
|
+
/**
|
|
58
|
+
* Determine whether a function's body (or expression body) is a "stub
|
|
59
|
+
* skeleton" — exactly one effective statement, and that statement is a
|
|
60
|
+
* constant return (or, for expression-bodied arrows, the body expression
|
|
61
|
+
* itself is a constant).
|
|
62
|
+
*
|
|
63
|
+
* Returns true when the function IS a stub skeleton.
|
|
64
|
+
* Returns false when the function has substantive subsequent behavior
|
|
65
|
+
* (the constant return is a guard clause, not a stub).
|
|
66
|
+
*/
|
|
67
|
+
declare function isStubSkeletonFunction(fnNode: any): boolean;
|
|
68
|
+
/**
|
|
69
|
+
* Walk a tree-sitter root node and collect the line numbers of all function
|
|
70
|
+
* bodies whose structure is NOT a pure stub skeleton. These are the lines
|
|
71
|
+
* where a regex `code-stub-return` finding should be suppressed, because
|
|
72
|
+
* the function has substantive subsequent behavior and the constant return
|
|
73
|
+
* is a guard clause.
|
|
74
|
+
*
|
|
75
|
+
* For expression-bodied arrows (where the body's range equals the arrow's
|
|
76
|
+
* own range), we add only the lines that are INSIDE the body expression
|
|
77
|
+
* itself, NOT the entire arrow's range — otherwise a curried arrow like
|
|
78
|
+
* `const f = () => () => null;` would suppress the inner stub's finding
|
|
79
|
+
* (because the outer arrow's range covers the inner arrow too).
|
|
80
|
+
*
|
|
81
|
+
* Recognized function-like node types:
|
|
82
|
+
* - TS/JS: `function_declaration`, `generator_function_declaration`,
|
|
83
|
+
* `method_definition`, `arrow_function`, `function_expression`,
|
|
84
|
+
* `generator_function`
|
|
85
|
+
* - Python: `function_definition`
|
|
86
|
+
*
|
|
87
|
+
* `method_definition` nodes with no body (abstract/declared methods) are
|
|
88
|
+
* skipped. Getters and setters classify by their body like normal methods.
|
|
89
|
+
*/
|
|
90
|
+
declare function collectNonStubBodyLines(rootNode: any): Set<number>;
|
|
39
91
|
/**
|
|
40
92
|
* Scan files for placeholder content (TODO/FIXME comments, stub implementations, etc.)
|
|
41
93
|
*/
|
|
42
94
|
export declare function placeholderScan(input: PlaceholderScanInput, directory: string): Promise<PlaceholderScanResult>;
|
|
43
95
|
export declare const placeholder_scan: ReturnType<typeof tool>;
|
|
96
|
+
/**
|
|
97
|
+
* Internal seam for direct testing of the body-shape walker without
|
|
98
|
+
* exercising the full placeholderScan pipeline. Mirrors the `_internals`
|
|
99
|
+
* pattern from `src/lang/backends/typescript.ts:343-351` (AGENTS.md
|
|
100
|
+
* invariant 7 — DI over `mock.module`).
|
|
101
|
+
*/
|
|
102
|
+
export declare const _internals: {
|
|
103
|
+
readonly collectNonStubBodyLines: typeof collectNonStubBodyLines;
|
|
104
|
+
readonly isStubSkeletonFunction: typeof isStubSkeletonFunction;
|
|
105
|
+
readonly isConstantLiteralNode: typeof isConstantLiteralNode;
|
|
106
|
+
};
|
|
107
|
+
export {};
|
|
@@ -59,6 +59,12 @@ export interface SastScanResult {
|
|
|
59
59
|
medium: number;
|
|
60
60
|
low: number;
|
|
61
61
|
};
|
|
62
|
+
/**
|
|
63
|
+
* Issue #2271 bug 3: present when every input was skipped for having no
|
|
64
|
+
* SAST language profile (non-code diff) — the scan passed because there
|
|
65
|
+
* was nothing to scan, and this counts the skipped non-code inputs.
|
|
66
|
+
*/
|
|
67
|
+
files_skipped_non_code?: number;
|
|
62
68
|
};
|
|
63
69
|
/** 'baseline_captured' when capture_baseline:true succeeded */
|
|
64
70
|
status?: 'baseline_captured' | 'baseline_merged';
|