opencode-swarm 7.154.2 → 7.154.3

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.
Files changed (72) hide show
  1. package/dist/cli/{coder-settlement-xqs49g07.js → coder-settlement-7c9h07f5.js} +7 -7
  2. package/dist/cli/{config-doctor-69eebk90.js → config-doctor-8zjz6dej.js} +2 -2
  3. package/dist/cli/{core-dyp14hcb.js → core-dn8bn81g.js} +1 -1
  4. package/dist/cli/{curation-policy-jm9jsxtt.js → curation-policy-2jkbybw7.js} +4 -4
  5. package/dist/cli/{curator-drift-h57z6tm3.js → curator-drift-g6w4ga1q.js} +1 -1
  6. package/dist/cli/{curator-llm-factory-5tq9c4v5.js → curator-llm-factory-mxdjw6kz.js} +28 -28
  7. package/dist/cli/{curator-he8n9z9n.js → curator-v12rhct2.js} +28 -28
  8. package/dist/cli/{evidence-summary-service-05s5y8d6.js → evidence-summary-service-zzvvcaa9.js} +10 -10
  9. package/dist/cli/{gate-evidence-3ptr9af3.js → gate-evidence-16jkjre9.js} +5 -5
  10. package/dist/cli/{guardrail-explain-tebk344k.js → guardrail-explain-11fx66cx.js} +29 -29
  11. package/dist/cli/{guardrail-log-x3gz3x17.js → guardrail-log-ahvfn58c.js} +3 -3
  12. package/dist/cli/{guardrail-reset-716pdyf5.js → guardrail-reset-zp5xe0n5.js} +28 -28
  13. package/dist/cli/{hive-promoter-nvwpj2t9.js → hive-promoter-k6y06jj8.js} +28 -28
  14. package/dist/cli/{index-kemxyzc0.js → index-0f4b9ywa.js} +1 -1
  15. package/dist/cli/{index-6rcx6vr6.js → index-2rgm3hgq.js} +4 -4
  16. package/dist/cli/{index-pj2nycpg.js → index-4dt91x6e.js} +1 -1
  17. package/dist/cli/{index-6qwp46k0.js → index-4n557t8w.js} +3 -3
  18. package/dist/cli/{index-xt6jx41g.js → index-6vcrkz80.js} +4 -4
  19. package/dist/cli/{index-vhhdj49x.js → index-7fyv62b2.js} +8 -9
  20. package/dist/cli/{index-2w6vy9a9.js → index-7qky94rr.js} +1 -1
  21. package/dist/cli/{index-6rns7b2m.js → index-94e20w95.js} +2 -2
  22. package/dist/cli/{index-v2ryvr8k.js → index-9nw6z98k.js} +30 -30
  23. package/dist/cli/{index-f6qmar4k.js → index-a6xjn2zt.js} +5 -5
  24. package/dist/cli/{index-j6q3k628.js → index-bhjkxasn.js} +1 -1
  25. package/dist/cli/{index-7tw116n6.js → index-ckp0z9d4.js} +2 -2
  26. package/dist/cli/{index-mnxtkt8s.js → index-d7r6y724.js} +3 -3
  27. package/dist/cli/{index-4cgee5vh.js → index-dtn0pne5.js} +20 -1
  28. package/dist/cli/{index-r0dactw2.js → index-ed13peqr.js} +1 -1
  29. package/dist/cli/{index-fv9ddfta.js → index-env8fk17.js} +1 -1
  30. package/dist/cli/{index-8v69hfpt.js → index-g1bh7980.js} +3 -3
  31. package/dist/cli/{index-ynvw5kxc.js → index-gbkdj7ay.js} +2 -2
  32. package/dist/cli/{index-nh4axsxc.js → index-kck2gtxk.js} +2 -2
  33. package/dist/cli/{index-bxvkn0ye.js → index-m0fy8jra.js} +93 -65
  34. package/dist/cli/{index-n0gqre56.js → index-n7nnz0jp.js} +6 -6
  35. package/dist/cli/{index-dm9tc6qb.js → index-q0prhdds.js} +1 -1
  36. package/dist/cli/{index-399e8aze.js → index-qdnmnq65.js} +1 -1
  37. package/dist/cli/{index-xq2v52tt.js → index-qxj63890.js} +1 -1
  38. package/dist/cli/{index-p7ey2w90.js → index-s23q9v6t.js} +6 -6
  39. package/dist/cli/{index-dsqat5pg.js → index-s5p8ryar.js} +1 -1
  40. package/dist/cli/{index-v9585wjc.js → index-v6xkgxts.js} +2 -2
  41. package/dist/cli/{index-4xqa0sgz.js → index-vntggpez.js} +2 -2
  42. package/dist/cli/{index-07n87ctw.js → index-wkagbmpt.js} +1 -1
  43. package/dist/cli/{index-57t97rtr.js → index-y3kw1zpm.js} +2 -1
  44. package/dist/cli/{index-9avdncr2.js → index-ymgsmjba.js} +5 -5
  45. package/dist/cli/{index-14bz2t7b.js → index-zak50rve.js} +1 -1
  46. package/dist/cli/index.js +28 -28
  47. package/dist/cli/{knowledge-escalator-s0tye368.js → knowledge-escalator-yew2fbxb.js} +10 -10
  48. package/dist/cli/{knowledge-events-eyy9yf6b.js → knowledge-events-zfg423hp.js} +8 -8
  49. package/dist/cli/{knowledge-link-rb11f06y.js → knowledge-link-ydv6shg2.js} +3 -3
  50. package/dist/cli/{knowledge-store-zjq5mz2d.js → knowledge-store-zcv9stzz.js} +4 -4
  51. package/dist/cli/{knowledge-validator-yw5qqqpd.js → knowledge-validator-q68wx2bf.js} +6 -6
  52. package/dist/cli/{pending-delegations-rdzjq3nw.js → pending-delegations-yet1rza6.js} +2 -2
  53. package/dist/cli/{pr-subscriptions-2f5fne6z.js → pr-subscriptions-mp7fyh1r.js} +3 -3
  54. package/dist/cli/{runner-yaqrj388.js → runner-s89ja08q.js} +4 -4
  55. package/dist/cli/{scan-cursor-8f0s883y.js → scan-cursor-38bzfhwf.js} +5 -5
  56. package/dist/cli/{schema-2xw94dh3.js → schema-9hqyt4t6.js} +1 -1
  57. package/dist/cli/{scope-persistence-tap2q94x.js → scope-persistence-dd9s9q2b.js} +5 -5
  58. package/dist/cli/{skill-generator-2xbfryqb.js → skill-generator-b28ezazm.js} +12 -12
  59. package/dist/cli/{worktree-collision-ownership-5gwey8ms.js → worktree-collision-ownership-zw65t2p9.js} +4 -4
  60. package/dist/cli/{worktree-isolation-xsy14t5a.js → worktree-isolation-0ag393t0.js} +28 -28
  61. package/dist/hooks/final-context-accounting.d.ts +60 -0
  62. package/dist/hooks/index.d.ts +1 -0
  63. package/dist/hooks/knowledge-injector.d.ts +1 -1
  64. package/dist/hooks/system-enhancer.d.ts +13 -0
  65. package/dist/hooks/utils.d.ts +11 -0
  66. package/dist/index.js +65 -60
  67. package/dist/services/compaction-service.d.ts +9 -3
  68. package/dist/services/context-budget-service.d.ts +7 -3
  69. package/dist/services/injection-budget.d.ts +103 -26
  70. package/dist/state.d.ts +69 -0
  71. package/dist/summaries/summarizer.d.ts +34 -3
  72. package/package.json +2 -1
@@ -7,9 +7,15 @@
7
7
  * - Reflection (default 60%): re-summarise into tighter format
8
8
  * - Emergency (default 80%): hard truncation to system + current task + last N turns
9
9
  *
10
- * Consumes the per-session budget pct recorded by system-enhancer.ts after
11
- * each budget calc (`getSessionBudgetPct`).
12
- * Never throws. Advisory system message injection via callback.
10
+ * Consumes the per-session FINAL PROMPT PRESSURE recorded by the final
11
+ * context-accounting step (#2107 §3) after every injector has run
12
+ * (`getFinalPromptPressure`); before that step has run for a session it falls
13
+ * back to the legacy injection-footprint pct (`getSessionBudgetPct`) so the
14
+ * tiers never go dark.
15
+ * Never throws. Advisory system message injection via callback. These tiers
16
+ * ADVISE the model to compact — they never compact anything themselves and
17
+ * never claim a compaction was performed (only the physical pruning in
18
+ * src/hooks/context-budget.ts actually removes content).
13
19
  */
14
20
  import type { CompactionConfig } from '../config/schema';
15
21
  export type { CompactionConfig };
@@ -74,10 +74,14 @@ export interface BudgetState {
74
74
  */
75
75
  export declare const DEFAULT_CONTEXT_BUDGET_CONFIG: ContextBudgetConfig;
76
76
  /**
77
- * Estimate token count for text using character-based approximation
77
+ * Estimate token count for text using the canonical character-based heuristic.
78
78
  *
79
- * @param text - The text to estimate tokens for
80
- * @returns Estimated token count (ceiling of chars / 3.5)
79
+ * Delegates to `estimateTokens` in src/hooks/utils.ts (issue #1616/#2107). This
80
+ * used to be an independent ÷3.5 formula, which made the user-facing budget
81
+ * report disagree ~15% with the injection-admission path (0.33 tok/char) on
82
+ * the same text. The export is kept for existing importers (capsule-builder,
83
+ * the services barrel); it is a heuristic — provider-reported token usage is
84
+ * authoritative when available.
81
85
  */
82
86
  export declare function estimateTokens(text: string): number;
83
87
  /**
@@ -1,8 +1,10 @@
1
1
  /**
2
2
  * Unified Injection Budget Service (FR-002).
3
3
  *
4
- * Pure, side-effect-free allocation function for the combined
5
- * system-enhancer + knowledge-injector injection ceiling.
4
+ * Two responsibilities: (1) the pure, side-effect-free FR-002 allocation
5
+ * function for the combined system-enhancer + knowledge-injector injection
6
+ * ceiling, and (2) the per-session/per-turn producer ledger (#2107 §2) that
7
+ * every model-visible producer claims from or records emissions into.
6
8
  *
7
9
  * Allocation strategy: proportional share.
8
10
  * - When combined demand fits within the budget, each component receives its
@@ -20,8 +22,8 @@
20
22
  * Priority-based allocation would require an arbitrary component ranking
21
23
  * not specified by the acceptance criteria.
22
24
  *
23
- * Char-to-token conversion uses the project's existing 0.33 tok/char ratio
24
- * (matches `estimateTokens` in src/hooks/utils.ts:200).
25
+ * Char-to-token conversion goes through the canonical estimator
26
+ * (`estimateTokensFromCharCount` in src/hooks/utils.ts — issue #1616/#2107).
25
27
  */
26
28
  /**
27
29
  * Allocation result for a single turn's unified injection budget.
@@ -59,40 +61,115 @@ export interface InjectionBudgetConfig {
59
61
  */
60
62
  export declare function allocateInjectionBudget(systemEnhancerDemandTokens: number, knowledgeInjectorDemandChars: number, config: InjectionBudgetConfig): InjectionBudgetAllocation;
61
63
  /**
62
- * Reset the budget for a session to the full unified ceiling.
63
- * Called by the first component to run for a given turn.
64
+ * Producers that contribute to the model-visible request surface. The
65
+ * `surface` on each accounting entry records WHERE the producer's bytes live:
66
+ * `'system'` entries are pushed to `output.system` in the system.transform
67
+ * chain (invisible to the messages chain and to final accounting's direct
68
+ * measurement of `output.messages` — they MUST be added to the final total via
69
+ * this ledger); `'messages'` entries are spliced into `output.messages` and are
70
+ * therefore already inside the final measurement (attribution only — adding
71
+ * them again would double-count).
64
72
  */
65
- export declare function resetUnifiedBudget(sessionID: string, totalBudget: number): void;
73
+ export type InjectionProducer = 'system-enhancer' | 'knowledge-injector' | 'context-capsule' | 'memory-recall' | 'advisory-queue' | 'swarm-command-banner' | 'linked-cohort-advisory' | 'spec-drift-advisory' | 'final-accounting-warning';
74
+ export type InjectionSurface = 'system' | 'messages';
75
+ export interface ProducerAccounting {
76
+ /** Tokens the producer asked the ledger for this turn (claims only). */
77
+ requested: number;
78
+ /** Tokens the ledger granted under the ceiling + local max (claims only). */
79
+ granted: number;
80
+ /** Tokens actually emitted to the model-visible surface. */
81
+ emitted: number;
82
+ /** Tokens the producer wanted but did not emit (its own pruning). */
83
+ truncated: number;
84
+ surface: InjectionSurface;
85
+ }
86
+ export interface TurnLedgerSummary {
87
+ generation: number;
88
+ totalBudget: number;
89
+ /** Ceiling enforcement is only active when `unified_injection_tokens` is configured. */
90
+ ceilingActive: boolean;
91
+ used: number;
92
+ producers: Array<{
93
+ producer: InjectionProducer;
94
+ } & ProducerAccounting>;
95
+ }
96
+ /**
97
+ * Begin a new turn ledger for a session: reset exactly once at the start of
98
+ * composing that request (the system-enhancer is the first producer and calls
99
+ * this). Mints a fresh generation, so any stale claim from a prior composition
100
+ * is discarded. `ceilingActive` is only true when
101
+ * `context_budget.unified_injection_tokens` is configured; when false the
102
+ * ledger records accounting but never denies a claim (default configs keep
103
+ * their pre-#2107 behavior).
104
+ */
105
+ export declare function beginTurnLedger(sessionID: string, totalBudget: number, ceilingActive: boolean): number;
106
+ /**
107
+ * Claim tokens from the turn ledger. The grant is bounded by the producer's
108
+ * own local maximum (`localMaxTokens`) and, only when the ceiling is active,
109
+ * by what remains of the unified ceiling. When NO ledger exists for the session
110
+ * (system-enhancer never ran this turn — native agent, first turn, or hook
111
+ * disabled), the claim fails open to the local maximum and is not recorded,
112
+ * preserving #1617's fail-open contract; the caller is expected to report that
113
+ * the hard ceiling was unavailable.
114
+ */
115
+ export declare function claimTurnBudget(sessionID: string, producer: InjectionProducer, requestedTokens: number, opts?: {
116
+ localMaxTokens?: number;
117
+ surface?: InjectionSurface;
118
+ }): {
119
+ granted: number;
120
+ ledgerPresent: boolean;
121
+ ceilingActive: boolean;
122
+ };
123
+ /**
124
+ * Record a producer's grant without claiming through `claimTurnBudget`.
125
+ *
126
+ * The system-enhancer and knowledge-injector enforce their split through the
127
+ * pure `allocateInjectionBudget` (FR-002 contract, pinned by tests) rather than
128
+ * sequential claims; this books their allocator-derived grants into the shared
129
+ * ceiling so later claimants (capsule, memory recall) draw from what actually
130
+ * remains. When the ceiling is inactive the grant is recorded but deducts
131
+ * nothing. The deduction is clamped to the remaining budget so `used` can never
132
+ * exceed `totalBudget`.
133
+ */
134
+ export declare function recordProducerGrant(sessionID: string, producer: InjectionProducer, requestedTokens: number, grantedTokens: number, surface: InjectionSurface): void;
66
135
  /**
67
- * Return the remaining unified budget for a session.
136
+ * Record what a producer actually emitted (and pruned itself) this turn.
137
+ * Producers that never claim (fixed/base content: advisory queue, banners,
138
+ * the context-budget warning, the final-accounting warning) still record their
139
+ * emission here so the final accounting can include them.
68
140
  */
69
- export declare function getUnifiedBudgetRemaining(sessionID: string): number;
141
+ export declare function recordProducerEmission(sessionID: string, producer: InjectionProducer, emittedTokens: number, truncatedTokens: number, surface: InjectionSurface): void;
70
142
  /**
71
- * Request a slice of the unified budget. Returns the granted token count.
72
- * If the requester's need exceeds the remaining budget, it gets the remainder
73
- * and the other source is implicitly blocked (remaining drops to 0).
143
+ * Snapshot of the session's current turn ledger (null when absent).
74
144
  */
75
- export declare function requestUnifiedBudget(sessionID: string, requestedTokens: number): number;
76
145
  /**
77
- * Return the total unified budget configured for a session (or 0 if unset).
146
+ * Deduct tokens from a producer's recorded emission (#2107 §3): downstream
147
+ * system-chain mutators (the role filter) REMOVE strings after the producer
148
+ * recorded them, and the final accounting must not count bytes the model
149
+ * never sees. Floors at zero; no-op without a ledger or producer entry.
78
150
  */
79
- export declare function getUnifiedBudgetTotal(sessionID: string): number;
151
+ export declare function deductProducerEmission(sessionID: string, producer: InjectionProducer, removedTokens: number): void;
152
+ export declare function getTurnLedgerSummary(sessionID: string): TurnLedgerSummary | null;
80
153
  /**
81
- * Remove a session's budget entry. Used for cleanup in tests.
154
+ * Emitted tokens recorded for one producer this turn (0 when no ledger or the
155
+ * producer has not run). Replaces the old `getSystemEnhancerDemand` relay: the
156
+ * knowledge-injector reads the system-enhancer's actual emission from here.
82
157
  */
83
- export declare function clearUnifiedBudget(sessionID: string): void;
158
+ export declare function getProducerEmission(sessionID: string, producer: InjectionProducer): number;
84
159
  /**
85
- * Ensure a budget entry exists for the session. Creates one with the full
86
- * budget if none exists; leaves an existing entry untouched.
160
+ * Advance the turn generation for a session: the current ledger is discarded so
161
+ * the next request composition starts from a fresh generation. Called when
162
+ * compaction changes the message surface (`experimental.session.compacting`)
163
+ * and at session teardown.
87
164
  */
88
- export declare function ensureSessionBudget(sessionID: string, totalBudget: number): void;
165
+ export declare function advanceTurnGeneration(sessionID: string): void;
89
166
  /**
90
- * Store the system-enhancer's actual per-turn token demand so that
91
- * knowledge-injector can read it and compute its proportional share.
167
+ * Test/maintenance hook: clear one session's ledger.
92
168
  */
93
- export declare function setSystemEnhancerDemand(sessionID: string, demand: number): void;
169
+ export declare function clearTurnLedger(sessionID: string): void;
94
170
  /**
95
- * Return the system-enhancer's actual per-turn token demand for a session.
96
- * Returns 0 if no budget entry exists or demand was not set.
171
+ * Clear every session's ledger. Called from `resetSwarmState` so the
172
+ * plugin-wide reset also resets per-turn producer accounting (zaxbysauce
173
+ * review on PR #2415: the reset pattern must cover ALL module-scoped maps).
97
174
  */
98
- export declare function getSystemEnhancerDemand(sessionID: string): number;
175
+ export declare function clearAllTurnLedgers(): void;
package/dist/state.d.ts CHANGED
@@ -723,6 +723,34 @@ export declare const swarmState: {
723
723
  pct: number;
724
724
  tokens: number;
725
725
  }>;
726
+ /**
727
+ * Final model-visible prompt pressure per session (#2107 §3) — the ONE
728
+ * truthful measurement taken after every injector has run and the system
729
+ * messages have been consolidated. Unlike `lastBudgetBySession` (the swarm
730
+ * INJECTION FOOTPRINT pct measured from an intermediate file surface),
731
+ * this is estimated total prompt tokens vs the same model limit physical
732
+ * pruning uses. Written by the final-context-accounting step; read by the
733
+ * compaction tiers, the CONTEXT PRESSURE advisory, and `/swarm status`.
734
+ * Bounded via {@link setFinalPromptPressure} (AGENTS.md invariant 8).
735
+ */
736
+ finalPromptPressureBySession: Map<string, {
737
+ pct: number;
738
+ usedTokens: number;
739
+ limitTokens: number;
740
+ estimatorSource: string;
741
+ providerReported: boolean;
742
+ }>;
743
+ /**
744
+ * Per-session final-accounting warning-band latch (#2107 §3): one bounded
745
+ * advisory per session per band (warn / critical). Kept here — not in the
746
+ * hook module — so `resetSwarmState` covers it like every other
747
+ * session-keyed map (AGENTS.md invariant 8). Bounded via
748
+ * {@link setFinalAccountingWarningBand}.
749
+ */
750
+ finalAccountingWarningBandsBySession: Map<string, {
751
+ warn: boolean;
752
+ critical: boolean;
753
+ }>;
726
754
  /**
727
755
  * Live `model.limit.context` per session — keyed by sessionID and bound to
728
756
  * the reporting model/provider identity. Recorded by the
@@ -1382,6 +1410,34 @@ export declare function getLiveContextModelIdentity(sessionID: string | undefine
1382
1410
  * written together so `/swarm status` can never pair a pct from one report
1383
1411
  * with a denominator from another. */
1384
1412
  export declare function setSessionBudget(sessionID: string, pct: number, tokens: number): void;
1413
+ /**
1414
+ * Record this session's final prompt pressure (#2107 §3), FIFO-evicting the
1415
+ * oldest entry past {@link MAX_TRACKED_BUDGET_SESSIONS}. Written once per request
1416
+ * composition by the final-context-accounting step.
1417
+ */
1418
+ export declare function setFinalPromptPressure(sessionID: string, snapshot: {
1419
+ pct: number;
1420
+ usedTokens: number;
1421
+ limitTokens: number;
1422
+ estimatorSource: string;
1423
+ providerReported: boolean;
1424
+ }): void;
1425
+ /** The session's final prompt pressure snapshot, or undefined when the final
1426
+ * accounting step has not run for it (e.g. native-agent sessions). */
1427
+ export declare function getFinalPromptPressure(sessionID: string | undefined): {
1428
+ pct: number;
1429
+ usedTokens: number;
1430
+ limitTokens: number;
1431
+ estimatorSource: string;
1432
+ providerReported: boolean;
1433
+ } | undefined;
1434
+ /** Record that this session's #2107 §3 advisory already fired for a band
1435
+ * (one advisory per session per band), FIFO-evicting past the cap. */
1436
+ export declare function setFinalAccountingWarningBand(sessionID: string, band: 'warn' | 'critical'): void;
1437
+ /** Whether this session already received the band's advisory. */
1438
+ export declare function getFinalAccountingWarningBand(sessionID: string | undefined, band: 'warn' | 'critical'): boolean;
1439
+ /** Clear all band latches (used by resetSwarmState and tests). */
1440
+ export declare function clearFinalAccountingWarningBands(): void;
1385
1441
  /** This session's last budget percentage, or 0 if it has not been measured.
1386
1442
  * Consumers that ACT on a session (compaction, the context-pressure advisory)
1387
1443
  * MUST use this rather than any cross-session aggregate. */
@@ -1397,6 +1453,19 @@ export declare function getDisplayBudget(): {
1397
1453
  pct: number;
1398
1454
  tokens: number;
1399
1455
  } | null;
1456
+ /**
1457
+ * The most-pressured session's FINAL prompt pressure snapshot, for
1458
+ * process-wide DISPLAY only (`/swarm status` has no single session in scope).
1459
+ * The snapshot is returned whole so the pct, used tokens, limit, and estimator
1460
+ * source shown together always come from one measurement (#2107 §3).
1461
+ */
1462
+ export declare function getDisplayFinalPromptPressure(): {
1463
+ pct: number;
1464
+ usedTokens: number;
1465
+ limitTokens: number;
1466
+ estimatorSource: string;
1467
+ providerReported: boolean;
1468
+ } | null;
1400
1469
  /** Set the critical shown ids for a session, FIFO-evicting the oldest entry
1401
1470
  * if the cap is exceeded. Re-setting an existing key keeps insertion order
1402
1471
  * fresh for that key (delete-then-set). */
@@ -44,11 +44,40 @@ declare function summarizeJsonArray(parsed: unknown[]): string;
44
44
  */
45
45
  declare function extractCodeSignatures(code: string): string[];
46
46
  /**
47
- * Build a preview for code output that includes declaration signatures.
47
+ * Codepoint-safe truncation to a UTF-8 byte budget (#2107 §5).
48
+ *
49
+ * Iterates code points (never UTF-16 units) so a multibyte CJK/emoji run can
50
+ * never be split mid-codepoint, and the result is deterministic across Bun and
51
+ * Node (which disagree on `Buffer.byteLength` for unpaired surrogates — per
52
+ * code point, both agree). Returns the kept text and the exact number of bytes
53
+ * omitted.
54
+ */
55
+ export declare function truncateToBytes(text: string, maxBytes: number): {
56
+ text: string;
57
+ omittedBytes: number;
58
+ };
59
+ /**
60
+ * Deterministic bounded head/tail preview (#2107 §5).
61
+ *
62
+ * Head: the leading non-blank identity lines (ceil half of the line budget).
63
+ * Tail: the trailing RAW outcome lines (floor half) — compiler, test, lint,
64
+ * and security verdicts live at the END of tool output, so the old head-only
65
+ * preview discarded exactly the decision-relevant evidence. Lines are never
66
+ * reordered within either segment, no outcome is invented, and every dropped
67
+ * region is disclosed with an accurate omitted-line count. When everything
68
+ * fits, the original text is returned unchanged (modulo per-line caps).
69
+ */
70
+ declare function headTailPreview(output: string, maxLines: number): string;
71
+ /**
72
+ * Build a preview for code output that includes declaration signatures plus
73
+ * the bounded head/tail policy (failure output at the end of a code blob is
74
+ * preserved).
48
75
  */
49
76
  declare function summarizeCode(output: string): string;
50
77
  /**
51
- * Build a preview for plain text output (leading non-blank lines).
78
+ * Build a preview for plain text output using the bounded head/tail policy
79
+ * (see headTailPreview). Previously head-only: the first `maxLines` non-blank
80
+ * lines, which silently discarded trailing failure/exit evidence.
52
81
  */
53
82
  declare function summarizeText(output: string, maxLines: number): string;
54
83
  /**
@@ -56,7 +85,7 @@ declare function summarizeText(output: string, maxLines: number): string;
56
85
  * @param output - The full tool output string
57
86
  * @param toolName - The name of the tool that produced the output
58
87
  * @param summaryId - Unique identifier for this summary
59
- * @param maxSummaryChars - Maximum characters allowed for the preview
88
+ * @param maxSummaryChars - Maximum bytes allowed for the preview
60
89
  * @returns Formatted summary string
61
90
  */
62
91
  export declare function createSummary(output: string, toolName: string, summaryId: string, maxSummaryChars: number): string;
@@ -64,6 +93,8 @@ export declare function createSummary(output: string, toolName: string, summaryI
64
93
  * Internal helpers exposed for testability.
65
94
  */
66
95
  export declare const _internals: {
96
+ truncateToBytes: typeof truncateToBytes;
97
+ headTailPreview: typeof headTailPreview;
67
98
  jsonTypeSignature: typeof jsonTypeSignature;
68
99
  summarizeJsonObject: typeof summarizeJsonObject;
69
100
  summarizeJsonArray: typeof summarizeJsonArray;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "opencode-swarm",
3
- "version": "7.154.2",
3
+ "version": "7.154.3",
4
4
  "description": "Architect-centric agentic swarm plugin for OpenCode - hub-and-spoke orchestration with SME consultation, code generation, and QA review",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -114,6 +114,7 @@
114
114
  "check:trajectory-store": "bun run scripts/check-trajectory-store-usage.ts",
115
115
  "check:mock-cleanup": "bun run scripts/check-mock-cleanup.ts",
116
116
  "check:invariants": "bun run scripts/check-invariants.ts",
117
+ "check:token-formula": "bun run scripts/check-token-formula.ts",
117
118
  "check:cross-contamination": "bun run scripts/check-cross-contamination.ts",
118
119
  "check:test-clock": "bun run scripts/check-test-clock.ts",
119
120
  "check:test-file-cap": "bun run scripts/check-test-file-cap.ts",