acp-kernel 0.0.94 → 0.0.95-pr.235.306
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/DESIGN.md +158 -137
- package/PROVENANCE.md +44 -40
- package/README.md +45 -32
- package/dist/boundaries.d.ts +3 -3
- package/dist/boundaries.d.ts.map +1 -1
- package/dist/cache-report.d.ts.map +1 -1
- package/dist/ccr.d.ts.map +1 -1
- package/dist/{chunk-NUQZKPQS.js → chunk-TQ6I62XC.js} +13 -6
- package/dist/chunk-TQ6I62XC.js.map +1 -0
- package/dist/compress-tools.d.ts +282 -254
- package/dist/compress-tools.d.ts.map +1 -1
- package/dist/compress.d.ts.map +1 -1
- package/dist/compression-rules.d.ts +9 -3
- package/dist/compression-rules.d.ts.map +1 -1
- package/dist/config.d.ts.map +1 -1
- package/dist/decompress.d.ts.map +1 -1
- package/dist/filter/apply.d.ts.map +1 -1
- package/dist/filter/index.d.ts +1 -1
- package/dist/filter/index.d.ts.map +1 -1
- package/dist/filter/types.d.ts.map +1 -1
- package/dist/handoff.d.ts.map +1 -1
- package/dist/hide-consumed.d.ts.map +1 -1
- package/dist/image-compress.d.ts.map +1 -1
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +477 -193
- package/dist/index.js.map +1 -1
- package/dist/message-kind.d.ts.map +1 -1
- package/dist/nudge-text.d.ts.map +1 -1
- package/dist/packs.d.ts +1 -1
- package/dist/packs.d.ts.map +1 -1
- package/dist/panel/cache.d.ts.map +1 -1
- package/dist/panel/index.js +29 -10
- package/dist/panel/index.js.map +1 -1
- package/dist/panel/panel.d.ts.map +1 -1
- package/dist/panel/topic.d.ts.map +1 -1
- package/dist/parse-compress-input.d.ts.map +1 -1
- package/dist/persist/index.d.ts +1 -1
- package/dist/persist/index.d.ts.map +1 -1
- package/dist/persist/index.js +49 -12
- package/dist/persist/index.js.map +1 -1
- package/dist/persist/state-merge.d.ts.map +1 -1
- package/dist/persist/store.d.ts.map +1 -1
- package/dist/protected.d.ts.map +1 -1
- package/dist/rebuild.d.ts.map +1 -1
- package/dist/recommend.d.ts.map +1 -1
- package/dist/render-refs.d.ts.map +1 -1
- package/dist/report.d.ts.map +1 -1
- package/dist/search/algorithms/bm25.d.ts.map +1 -1
- package/dist/search/algorithms/fuzzy.d.ts.map +1 -1
- package/dist/search/algorithms/hybrid.d.ts.map +1 -1
- package/dist/search/algorithms/semantic.d.ts.map +1 -1
- package/dist/search/algorithms/substring.d.ts.map +1 -1
- package/dist/search/doc-cache.d.ts.map +1 -1
- package/dist/search/index.d.ts +1 -1
- package/dist/search/index.d.ts.map +1 -1
- package/dist/search/registry.d.ts.map +1 -1
- package/dist/search/stemmer.d.ts.map +1 -1
- package/dist/search/tokenizer.d.ts.map +1 -1
- package/dist/search/types.d.ts.map +1 -1
- package/dist/search.d.ts +3 -3
- package/dist/search.d.ts.map +1 -1
- package/dist/segment.d.ts +33 -0
- package/dist/segment.d.ts.map +1 -0
- package/dist/surface-config.d.ts.map +1 -1
- package/dist/tool-pairs.d.ts.map +1 -1
- package/dist/truncate-tools.d.ts.map +1 -1
- package/dist/truncate.d.ts.map +1 -1
- package/dist/turn-integrity.d.ts.map +1 -1
- package/dist/wire/anthropic.d.ts.map +1 -1
- package/dist/wire/bili-message.d.ts.map +1 -1
- package/dist/wire/compress-detect.d.ts.map +1 -1
- package/dist/wire/demoted-thinking.d.ts.map +1 -1
- package/dist/wire/formats.d.ts.map +1 -1
- package/dist/wire/index.js +476 -129
- package/dist/wire/index.js.map +1 -1
- package/dist/wire/message-id.d.ts.map +1 -1
- package/dist/wire/mirror.d.ts.map +1 -1
- package/dist/wire/openai.d.ts.map +1 -1
- package/dist/wire/responses.d.ts.map +1 -1
- package/dist/wire/strip-images.d.ts.map +1 -1
- package/dist/wire/util.d.ts.map +1 -1
- package/package.json +66 -66
- package/dist/chunk-NUQZKPQS.js.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"message-kind.d.ts","sourceRoot":"","sources":["../src/message-kind.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAE9C;;;;;;;GAOG;AACH,wBAAgB,aAAa,CAAC,OAAO,EAAE,WAAW,GAAG,OAAO,
|
|
1
|
+
{"version":3,"file":"message-kind.d.ts","sourceRoot":"","sources":["../src/message-kind.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAE9C;;;;;;;GAOG;AACH,wBAAgB,aAAa,CAAC,OAAO,EAAE,WAAW,GAAG,OAAO,CAI3D"}
|
package/dist/nudge-text.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"nudge-text.d.ts","sourceRoot":"","sources":["../src/nudge-text.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,
|
|
1
|
+
{"version":3,"file":"nudge-text.d.ts","sourceRoot":"","sources":["../src/nudge-text.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,aAAa,EACb,iBAAiB,EACjB,cAAc,EAIf,MAAM,YAAY,CAAC;AAEpB,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAE5C,MAAM,MAAM,UAAU,GAAG,QAAQ,GAAG,WAAW,CAAC;AAEhD,MAAM,WAAW,mBAAmB;IAClC,cAAc,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC/B,eAAe,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAC5B;AAED,MAAM,WAAW,aAAa;IAC5B,KAAK,EAAE,UAAU,CAAC;IAClB,IAAI,EAAE,MAAM,CAAC;CACd;AA8DD,wBAAgB,YAAY,CAC1B,YAAY,EAAE,iBAAiB,EAAE,EACjC,eAAe,EAAE,cAAc,EAAE,GAChC,MAAM,CAsHR;AAoBD,wBAAgB,eAAe,CAC7B,QAAQ,EAAE,aAAa,EACvB,OAAO,GAAE,OAAwB,EACjC,QAAQ,GAAE,mBAAwB,GACjC,aAAa,CA6Ef"}
|
package/dist/packs.d.ts
CHANGED
|
@@ -64,7 +64,7 @@ export declare const defaultPack: Pack;
|
|
|
64
64
|
* reply as sent, then pattern-completed the list into a fabricated user turn.
|
|
65
65
|
* Summaries are the only record; this contract is the floor that keeps them honest.
|
|
66
66
|
*/
|
|
67
|
-
export declare const LEAN_HOW_TO_COMPRESS = "HOW TO COMPRESS\n\nYour summary is the ONLY record of the replaced conversation \u2014 a later reader must continue without the original. It records the PAST: label task state as history (\"TASK AS OF THIS BLOCK: ...\"), never as a live instruction. Real unicode only, never \\uXXXX escapes.\n\nINTEGRITY \u2014 record facts and state only, never a simulated transcript of the dialogue: no Q&A lists, no \"(answered)\" claims. An answer not actually sent is PENDING; user questions are recorded as asked (with ref), never as answered.\n\nKEEP VERBATIM \u2014 never paraphrase or abbreviate:\n- File paths with line numbers and directory prefix on every mention (lib/hooks.ts:347); never a bare filename \u2014 ambiguous, un-greppable.\n- Function/class/type signatures AND the critical code lines that encode logic (the line that IS the finding).\n- Error messages and stack traces (exact text \u2014 needed to grep later).\n- Report details: comparison numbers plus mechanism, not \"X is worse\" (\"1.76\u00D7 PPL gap because KV store is static\").\n- Decisions with rationale (\"chose X over Y because Z\"); discovered constraints (\"must support Node 22\").\n- Exact values: versions, config keys, thresholds, magic numbers.\n- User intent: short quotes verbatim ONLY WITH message ref (User said (m00132): \"ship it tonight\"); without a ref, paraphrase. Quotes are history,
|
|
67
|
+
export declare const LEAN_HOW_TO_COMPRESS = "HOW TO COMPRESS\n\nYour summary is the ONLY record of the replaced conversation \u2014 a later reader must continue without the original. It records the PAST: label task state as history (\"TASK AS OF THIS BLOCK: ...\"), never as a live instruction. Real unicode only, never \\uXXXX escapes.\n\nINTEGRITY \u2014 record facts and state only, never a simulated transcript of the dialogue: no Q&A lists, no \"(answered)\" claims. An answer not actually sent is PENDING; user questions are recorded as asked (with ref), never as answered.\n\nKEEP VERBATIM \u2014 never paraphrase or abbreviate:\n- File paths with line numbers and directory prefix on every mention (lib/hooks.ts:347); never a bare filename \u2014 ambiguous, un-greppable.\n- Function/class/type signatures AND the critical code lines that encode logic (the line that IS the finding).\n- Error messages and stack traces (exact text \u2014 needed to grep later).\n- Report details: comparison numbers plus mechanism, not \"X is worse\" (\"1.76\u00D7 PPL gap because KV store is static\").\n- Decisions with rationale (\"chose X over Y because Z\"); discovered constraints (\"must support Node 22\").\n- Exact values: versions, config keys, thresholds, magic numbers.\n- User intent: short quotes verbatim ONLY WITH message ref (User said (m00132): \"ship it tonight\"); without a ref, paraphrase. Quotes are history, not live instructions \u2014 but open-objective STATUS is current (see Open objectives below); never change scope, constraints, priorities, acceptance criteria, outcomes.\n- Overall goal and its evolution, including pivots (\"initially: fix X \u2192 pivoted to: refactor Y\").\n- Purpose behind significant actions (hypothesis, question, goal \u2014 not just what was done).\n- Open questions and unresolved TODOs.\n- Open objectives: user-requested work neither completed nor superseded gets a one-line \"Open objectives:\" entry with message refs; scan absorbed block summaries too. Last to drop, first to restore at every tier \u2014 carrying is not a directive to re-execute unconfirmed.\n- Message refs of key anchors (m00420, m00510\u2013m00520) for decompress.\n\nDROP \u2014 keep the signal, discard the vessel: verbose logs once the error/result is captured; duplicate reads; consumed exploration (search hits, agent returns, successful outputs); dead ends (one lesson line: \"tried X, failed because Y\"); back-and-forth once the final position is kept; repeated status checks. For each dropped item add one line of CONTENT: what it covers (\"probe.py: tests n-gram baseline...\"), not where it lives.\n\nPRIORITY when compacting: 1. user goal/evolution/intent/hard constraints \u00B7 2. decisions + rationale \u00B7 3. exact artifacts (paths, signatures, errors, values) \u00B7 4. conclusions \u00B7 5. lessons learned (what failed and why).\n\nFormat: dense scannable bullets under short thematic headers, not narrative prose; every line earns its place. Do not mimic the style of existing summaries in context; follow these rules.";
|
|
68
68
|
/** Token-lean surface: one-line tool descriptions, no snippets or guidelines.
|
|
69
69
|
* Host-specific trims (e.g. the Pi adapter's compact system-prompt block)
|
|
70
70
|
* ride under `adapters` and are validated by that host. The pi
|
package/dist/packs.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"packs.d.ts","sourceRoot":"","sources":["../src/packs.ts"],"names":[],"mappings":"AAgBA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAC5C,OAAO,KAAK,EAAE,sBAAsB,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAC/E,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,iBAAiB,CAAC;AAE3D;sEACsE;AACtE,MAAM,WAAW,cAAc;IAC7B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB;4EACwE;IACxE,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAED,mDAAmD;AACnD,MAAM,WAAW,WAAW;IAC1B,OAAO,CAAC,EAAE,OAAO,CAAC,OAAO,CAAC,CAAC;IAC3B,cAAc,CAAC,EAAE,sBAAsB,CAAC;IACxC,aAAa,CAAC,EAAE,mBAAmB,CAAC;IACpC,WAAW,CAAC,EAAE,WAAW,CAAC;IAC1B,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACpC;AAED;oEACoE;AACpE,MAAM,WAAW,IAAI;IACnB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,OAAO,EAAE,WAAW,CAAC;IACrB,MAAM,EAAE,MAAM,CAAC;CAChB;AAED;;gBAEgB;AAChB,MAAM,WAAW,UAAU;IACzB,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,OAAO,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,GAAG,IAAI,CAAC;IACnC,IAAI,CAAC,IAAI,IAAI,EAAE,CAAC;CACjB;AAED,sDAAsD;AACtD,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,OAAO,EAAE,SAAS,UAAU,EAAE,CAAC;IACxC,OAAO,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,GAAG,IAAI,CAAC;IACnC,SAAS,IAAI,IAAI,EAAE,CAAC;CACrB;
|
|
1
|
+
{"version":3,"file":"packs.d.ts","sourceRoot":"","sources":["../src/packs.ts"],"names":[],"mappings":"AAgBA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAC5C,OAAO,KAAK,EAAE,sBAAsB,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAC/E,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,iBAAiB,CAAC;AAE3D;sEACsE;AACtE,MAAM,WAAW,cAAc;IAC7B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB;4EACwE;IACxE,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAED,mDAAmD;AACnD,MAAM,WAAW,WAAW;IAC1B,OAAO,CAAC,EAAE,OAAO,CAAC,OAAO,CAAC,CAAC;IAC3B,cAAc,CAAC,EAAE,sBAAsB,CAAC;IACxC,aAAa,CAAC,EAAE,mBAAmB,CAAC;IACpC,WAAW,CAAC,EAAE,WAAW,CAAC;IAC1B,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACpC;AAED;oEACoE;AACpE,MAAM,WAAW,IAAI;IACnB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,OAAO,EAAE,WAAW,CAAC;IACrB,MAAM,EAAE,MAAM,CAAC;CAChB;AAED;;gBAEgB;AAChB,MAAM,WAAW,UAAU;IACzB,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,OAAO,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,GAAG,IAAI,CAAC;IACnC,IAAI,CAAC,IAAI,IAAI,EAAE,CAAC;CACjB;AAED,sDAAsD;AACtD,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,OAAO,EAAE,SAAS,UAAU,EAAE,CAAC;IACxC,OAAO,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,GAAG,IAAI,CAAC;IACnC,SAAS,IAAI,IAAI,EAAE,CAAC;CACrB;AAuBD,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAErD;AAgBD;;4EAE4E;AAC5E,wBAAgB,mBAAmB,CACjC,GAAG,EAAE,cAAc,GAAG,IAAI,GAAG,SAAS,GACrC,WAAW,CAoDb;AAED,mEAAmE;AACnE,eAAO,MAAM,WAAW,EAAE,IAMzB,CAAC;AA8BF;;;;;;;;;;GAUG;AACH,eAAO,MAAM,oBAAoB,k9FAwB2J,CAAC;AAE7L;;;;;2CAK2C;AAC3C,eAAO,MAAM,QAAQ,EAAE,IA6CtB,CAAC;AASF,eAAO,MAAM,aAAa,EAAE,UAQ3B,CAAC;AAaF;0EAC0E;AAC1E,wBAAgB,mBAAmB,CAAC,EAAE,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,UAAU,CAqCvE;AAED,0EAA0E;AAC1E,wBAAgB,kBAAkB,CAChC,OAAO,EAAE,SAAS,UAAU,EAAE,GAC7B,YAAY,CAyBd;AAED;;0BAE0B;AAC1B,wBAAgB,kBAAkB,CAAC,IAAI,EAAE;IACvC,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;CAC9B,GAAG,UAAU,EAAE,CAQf"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cache.d.ts","sourceRoot":"","sources":["../../src/panel/cache.ts"],"names":[],"mappings":"AAAA;;;;;;;kCAOkC;AAElC,MAAM,WAAW,gBAAgB;IAC/B,mEAAmE;IACnE,KAAK,EAAE,MAAM,CAAC;IACd,wDAAwD;IACxD,SAAS,EAAE,MAAM,CAAC;IAClB,wEAAwE;IACxE,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,eAAe;IAC9B;6DACyD;IACzD,OAAO,EAAE,MAAM,GAAG,SAAS,CAAC;IAC5B;4DACwD;IACxD,IAAI,EAAE,MAAM,GAAG,SAAS,CAAC;IACzB,2DAA2D;IAC3D,QAAQ,EAAE,MAAM,CAAC;IACjB,2CAA2C;IAC3C,SAAS,EAAE,MAAM,CAAC;IAClB,wEAAwE;IACxE,YAAY,EAAE,MAAM,CAAC;CACtB;AAMD,oEAAoE;AACpE,wBAAgB,aAAa,
|
|
1
|
+
{"version":3,"file":"cache.d.ts","sourceRoot":"","sources":["../../src/panel/cache.ts"],"names":[],"mappings":"AAAA;;;;;;;kCAOkC;AAElC,MAAM,WAAW,gBAAgB;IAC/B,mEAAmE;IACnE,KAAK,EAAE,MAAM,CAAC;IACd,wDAAwD;IACxD,SAAS,EAAE,MAAM,CAAC;IAClB,wEAAwE;IACxE,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,eAAe;IAC9B;6DACyD;IACzD,OAAO,EAAE,MAAM,GAAG,SAAS,CAAC;IAC5B;4DACwD;IACxD,IAAI,EAAE,MAAM,GAAG,SAAS,CAAC;IACzB,2DAA2D;IAC3D,QAAQ,EAAE,MAAM,CAAC;IACjB,2CAA2C;IAC3C,SAAS,EAAE,MAAM,CAAC;IAClB,wEAAwE;IACxE,YAAY,EAAE,MAAM,CAAC;CACtB;AAMD,oEAAoE;AACpE,wBAAgB,aAAa,CAC3B,MAAM,EAAE,SAAS,gBAAgB,EAAE,GAClC,eAAe,CAyBjB;AAED,qEAAqE;AACrE,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAElD"}
|
package/dist/panel/index.js
CHANGED
|
@@ -3,7 +3,7 @@ import {
|
|
|
3
3
|
defaultCountTokens,
|
|
4
4
|
formatRanges,
|
|
5
5
|
viableRanges
|
|
6
|
-
} from "../chunk-
|
|
6
|
+
} from "../chunk-TQ6I62XC.js";
|
|
7
7
|
|
|
8
8
|
// src/panel/topic.ts
|
|
9
9
|
function topicFallback(summary) {
|
|
@@ -57,7 +57,10 @@ function formatHitRate(rate) {
|
|
|
57
57
|
// src/panel/panel.ts
|
|
58
58
|
function bar(value, total, width = 20) {
|
|
59
59
|
if (total === 0) return "";
|
|
60
|
-
const filled = Math.max(
|
|
60
|
+
const filled = Math.max(
|
|
61
|
+
0,
|
|
62
|
+
Math.min(width, Math.round(value / total * width))
|
|
63
|
+
);
|
|
61
64
|
return "\u2588".repeat(filled) + "\u2591".repeat(width - filled);
|
|
62
65
|
}
|
|
63
66
|
function buildStatusPanel(input) {
|
|
@@ -80,16 +83,22 @@ function buildStatusPanel(input) {
|
|
|
80
83
|
lines.push("\u2570\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u256F");
|
|
81
84
|
if (input.version) lines.push(input.version);
|
|
82
85
|
lines.push("");
|
|
83
|
-
lines.push(
|
|
86
|
+
lines.push(
|
|
87
|
+
`Context (session accounting, host footer scale): ${displayPct}% (${fmt(displayTotal)} / ${fmt(limit)}) \u2014 includes compressed originals; shrinks slower than the sent view`
|
|
88
|
+
);
|
|
84
89
|
if (nudge && bd) {
|
|
85
90
|
const growth = bd.growth;
|
|
86
91
|
if (growth > 0 && displayTotal > 0) {
|
|
87
92
|
lines.push(`Growth: +${fmt(growth)} since last nudge`);
|
|
88
93
|
}
|
|
89
94
|
lines.push("");
|
|
90
|
-
lines.push(
|
|
95
|
+
lines.push(
|
|
96
|
+
`Sent to LLM (after compression, est.): ${fmt(sentTotal)}${limit > 0 ? ` (${sentPct}% of limit)` : ""}`
|
|
97
|
+
);
|
|
91
98
|
if (input.unprunedTokens !== void 0 && sessionOnly > 0) {
|
|
92
|
-
lines.push(
|
|
99
|
+
lines.push(
|
|
100
|
+
`Session-only (compressed originals, est.): ${fmt(sessionOnly)} \u2014 pruned from every request; the footer/nudge still count them`
|
|
101
|
+
);
|
|
93
102
|
}
|
|
94
103
|
lines.push("");
|
|
95
104
|
lines.push("Token Breakdown (sent view):");
|
|
@@ -104,7 +113,9 @@ function buildStatusPanel(input) {
|
|
|
104
113
|
if (cat.value <= 0) continue;
|
|
105
114
|
const pct = sentTotal > 0 ? Math.round(cat.value / sentTotal * 100) : 0;
|
|
106
115
|
const b = bar(cat.value, sentTotal);
|
|
107
|
-
lines.push(
|
|
116
|
+
lines.push(
|
|
117
|
+
` ${cat.label.padEnd(10)} ${b} ${String(pct).padStart(3)}% ${fmt(cat.value)}`
|
|
118
|
+
);
|
|
108
119
|
}
|
|
109
120
|
}
|
|
110
121
|
if (input.cacheUsages) {
|
|
@@ -133,22 +144,30 @@ function buildStatusPanel(input) {
|
|
|
133
144
|
}
|
|
134
145
|
if (activeBlocksList.length > 0) {
|
|
135
146
|
lines.push("");
|
|
136
|
-
lines.push(
|
|
147
|
+
lines.push(
|
|
148
|
+
`Blocks: ${activeBlocksList.length} active / ${totalBlocksList.length} total (${fmt(state.stats.tokensCompressed)} tokens compressed, cumulative)`
|
|
149
|
+
);
|
|
137
150
|
for (const b of activeBlocksList) {
|
|
138
151
|
const topic = b.topic ? `: ${b.topic}` : `: ${topicFallback(b.summary || "")}`;
|
|
139
152
|
const summaryTok = defaultCountTokens(b.summary || "");
|
|
140
153
|
const origTok = b.compressedTokens > 0 ? b.compressedTokens : summaryTok;
|
|
141
|
-
lines.push(
|
|
154
|
+
lines.push(
|
|
155
|
+
` [${b.blockId}] T${b.tier} ${fmt(origTok)}\u2192${fmt(summaryTok)}${topic}`
|
|
156
|
+
);
|
|
142
157
|
}
|
|
143
158
|
} else if (totalBlocksList.length > 0) {
|
|
144
159
|
lines.push("");
|
|
145
|
-
lines.push(
|
|
160
|
+
lines.push(
|
|
161
|
+
`Blocks: 0 active / ${totalBlocksList.length} total (${fmt(state.stats.tokensCompressed)} tokens compressed, cumulative)`
|
|
162
|
+
);
|
|
146
163
|
} else {
|
|
147
164
|
lines.push("");
|
|
148
165
|
lines.push("Blocks: none (nothing compressed yet)");
|
|
149
166
|
}
|
|
150
167
|
lines.push("");
|
|
151
|
-
lines.push(
|
|
168
|
+
lines.push(
|
|
169
|
+
"Tag visibility: tags injected to LLM only (deep copy), not persisted in session, not shown in terminal."
|
|
170
|
+
);
|
|
152
171
|
return lines.join("\n");
|
|
153
172
|
}
|
|
154
173
|
export {
|
package/dist/panel/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/panel/topic.ts","../../src/panel/format.ts","../../src/panel/cache.ts","../../src/panel/panel.ts"],"sourcesContent":["/** Short topic for a block when the model did not provide one: first sentence\n * segment, leading quotes stripped, truncated to 30 chars with an ellipsis.\n * Used wherever block lists are rendered (panels, search results). */\nimport { clampPrefix } from \"../truncate.js\";\n\nexport function topicFallback(summary: string): string {\n const first = summary.split(/[.\\n]/)[0] ?? \"\";\n const t = first.trim().replace(/^[\"'`]+/, \"\").trim();\n return t.length <= 30 ? t : `${clampPrefix(t, 30).trimEnd()}…`;\n}\n","/** Compact token formatting for user-facing panels: lowercase k/M with the\n * same thresholds as the hosts' footers (<1000 → raw, <10000 → one decimal\n * k, <1e6 → rounded k, <1e7 → one decimal M). */\nexport function formatCompactTokens(count: number): string {\n if (count < 1000) return count.toString();\n if (count < 10000) return `${(count / 1000).toFixed(1)}k`;\n if (count < 1000000) return `${Math.round(count / 1000)}k`;\n if (count < 10000000) return `${(count / 1000000).toFixed(1)}M`;\n return `${Math.round(count / 1000000)}M`;\n}\n","/** Cache hit-rate math for the /acp status panel.\n *\n * Hosts feed per-request prompt-cache usage samples (from assistant\n * messages' provider-reported `usage`); the kernel derives the display\n * numbers. A request COUNTS only when the provider reported cache\n * activity for it (`cacheRead + cacheWrite > 0`): providers without\n * prompt-cache reporting (0/0 with plain `input`) must not drag the\n * average to a fabricated 0%. */\n\nexport interface CacheUsageSample {\n /** Non-cached conversation input tokens billed for the request. */\n input: number;\n /** Conversation tokens served from the prompt cache. */\n cacheRead: number;\n /** Conversation tokens written to the prompt cache (cache creation). */\n cacheWrite: number;\n}\n\nexport interface CacheHitSummary {\n /** Session hit rate (0..1), weighted by billed prompt tokens.\n * Undefined when no request reported cache activity. */\n session: number | undefined;\n /** Hit rate (0..1) of the most recent request that reported cache\n * activity. Undefined when no request reported any. */\n last: number | undefined;\n /** Counted requests (provider reported cache activity). */\n requests: number;\n /** Cumulative tokens served from cache. */\n cacheRead: number;\n /** Cumulative billed prompt tokens (input + cacheRead + cacheWrite). */\n billedPrompt: number;\n}\n\nfunction num(v: unknown): number {\n return typeof v === \"number\" && Number.isFinite(v) && v > 0 ? v : 0;\n}\n\n/** Aggregate per-request cache usage into panel display numbers. */\nexport function cacheHitStats(usages: readonly CacheUsageSample[]): CacheHitSummary {\n let cacheRead = 0;\n let billedPrompt = 0;\n let requests = 0;\n let last: number | undefined;\n for (const u of usages) {\n const read = num(u?.cacheRead);\n const write = num(u?.cacheWrite);\n const input = num(u?.input);\n // No cache signal on this request → excluded entirely (see header).\n if (read + write <= 0) continue;\n const total = read + write + input;\n if (total <= 0) continue;\n cacheRead += read;\n billedPrompt += total;\n requests += 1;\n last = read / total;\n }\n return {\n session: requests > 0 ? cacheRead / billedPrompt : undefined,\n last,\n requests,\n cacheRead,\n billedPrompt,\n };\n}\n\n/** Format a 0..1 rate as a percentage with one decimal (\"92.3%\"). */\nexport function formatHitRate(rate: number): string {\n return `${(Math.max(0, Math.min(1, rate)) * 100).toFixed(1)}%`;\n}\n","import { defaultCountTokens } from \"../tokenize.js\";\nimport { formatRanges } from \"../nudge-text.js\";\nimport type { CompressionState, NudgeDecision } from \"../types.js\";\nimport { formatCompactTokens } from \"./format.js\";\nimport { topicFallback } from \"./topic.js\";\nimport { viableRanges } from \"../viable.js\";\nimport { cacheHitStats, formatHitRate, type CacheUsageSample } from \"./cache.js\";\n\nexport interface StatusPanelInput {\n /** Adapter identifier for the header, e.g. \"billion-context-omp@0.1.6\".\n * Omit to hide the version line. */\n version?: string;\n /** Host session accounting — the SAME number the host footer displays.\n * It includes compressed originals (summaries stay in the window), so it\n * shrinks slower than the sent view when compression prunes the\n * per-request projection. */\n tokenCount: number;\n /** Measured token count of the host system prompt (host-specific to\n * obtain; the kernel breakdown does not see it). */\n systemPromptTokens: number;\n /** Kernel state (blocks drive the Blocks section). */\n state: CompressionState;\n /** The nudge decision from core.processTurn for this turn, if any. The\n * panel applies the viability filter to compressibleRanges itself. */\n nudge: NudgeDecision | undefined;\n /** Configured model context window, in tokens. */\n modelContextLimit: number;\n /** Estimate of the FULL (unpruned) core-message projection, computed\n * with the SAME countTokens the core uses (kernel default = CJK-aware\n * defaultCountTokens) — the same estimation scale as the kernel\n * breakdown. When provided, the panel derives `Session-only` on that\n * scale (unpruned − sent). Without it the line is omitted: subtracting\n * the host's provider-scale number from an estimate-scale number\n * invents a third, meaningless scale (issue #18 \"看板统计的和拆分的有差异\"). */\n unprunedTokens?: number;\n /** Per-request prompt-cache usage (from assistant messages' provider-\n * reported `usage`). Requests without cache reporting are excluded by\n * cacheHitStats; when no counted request remains, the section is\n * omitted entirely. Omit the field to hide the section. */\n cacheUsages?: ReadonlyArray<CacheUsageSample>;\n /** Token formatter override (defaults to formatCompactTokens). */\n fmtTokens?: (n: number) => string;\n}\n\nfunction bar(value: number, total: number, width: number = 20): string {\n if (total === 0) return \"\";\n const filled = Math.max(0, Math.min(width, Math.round((value / total) * width)));\n return \"█\".repeat(filled) + \"░\".repeat(width - filled);\n}\n\n/** Render the /acp status panel. Three token numbers, each labeled with\n * its own scale, never mixed in arithmetic:\n * - Session accounting (host footer scale): the host's reported context\n * size INCLUDING compressed originals (summaries stay in the window), so\n * it shrinks slower than the sent view when compression prunes the\n * per-request projection.\n * - Sent view (estimated, kernel countTokens scale): what actually\n * reaches the LLM after compression (kernel's classification over the\n * pruned projection + measured system prompt). This is the number\n * compression controls.\n * - Session-only (estimated, kernel countTokens scale): unpruned\n * projection − sent view; the compressed originals pruned from every\n * request.\n * Subtracting the host number from an estimate produced numbers that\n * reconciled with neither scale (\"Framework 390K\", \"session-only 29k vs\n * 112k compressed\") — that is what issue #18 reported. */\nexport function buildStatusPanel(input: StatusPanelInput): string {\n const { tokenCount, state, nudge, modelContextLimit } = input;\n const fmt = input.fmtTokens ?? formatCompactTokens;\n const bd = nudge?.contextBreakdown;\n const limit = modelContextLimit;\n const classified = bd ? bd.system + bd.tool + bd.summaries + bd.code + bd.text : 0;\n const systemPromptTokens = input.systemPromptTokens;\n const sentTotal = classified + systemPromptTokens;\n // Same-scale derivation only: both sides use the core's countTokens\n // estimate (kernel default = CJK-aware defaultCountTokens). The host\n // footer's tokenCount (provider-anchored, session-tree) is displayed as\n // its own line and never fed into an arithmetic difference with these.\n const sessionOnly = input.unprunedTokens !== undefined ? Math.max(0, input.unprunedTokens - sentTotal) : 0;\n const displayTotal = tokenCount;\n const displayPct = limit > 0 ? Math.round((displayTotal / limit) * 100) : 0;\n const sentPct = limit > 0 ? Math.round((sentTotal / limit) * 100) : 0;\n const activeBlocksList = state.blocks.filter((b) => b.active);\n const totalBlocksList = state.blocks;\n\n const lines: string[] = [];\n\n lines.push(\"╭─────────────────────────────────────────────╮\");\n lines.push(\"│ ACP Context Analysis │\");\n lines.push(\"╰─────────────────────────────────────────────╯\");\n if (input.version) lines.push(input.version);\n lines.push(\"\");\n lines.push(`Context (session accounting, host footer scale): ${displayPct}% (${fmt(displayTotal)} / ${fmt(limit)}) — includes compressed originals; shrinks slower than the sent view`);\n\n if (nudge && bd) {\n const growth = bd.growth;\n if (growth > 0 && displayTotal > 0) {\n lines.push(`Growth: +${fmt(growth)} since last nudge`);\n }\n lines.push(\"\");\n lines.push(`Sent to LLM (after compression, est.): ${fmt(sentTotal)}${limit > 0 ? ` (${sentPct}% of limit)` : \"\"}`);\n if (input.unprunedTokens !== undefined && sessionOnly > 0) {\n lines.push(`Session-only (compressed originals, est.): ${fmt(sessionOnly)} — pruned from every request; the footer/nudge still count them`);\n }\n lines.push(\"\");\n lines.push(\"Token Breakdown (sent view):\");\n\n const categories: Array<{ label: string; value: number }> = [\n { label: \"Tool\", value: bd.tool },\n { label: \"SysPrompt\", value: systemPromptTokens },\n { label: \"Text\", value: bd.text },\n { label: \"Code\", value: bd.code },\n { label: \"Summaries\", value: bd.summaries },\n ];\n\n for (const cat of categories) {\n if (cat.value <= 0) continue;\n const pct = sentTotal > 0 ? Math.round((cat.value / sentTotal) * 100) : 0;\n const b = bar(cat.value, sentTotal);\n lines.push(` ${cat.label.padEnd(10)} ${b} ${String(pct).padStart(3)}% ${fmt(cat.value)}`);\n }\n }\n\n if (input.cacheUsages) {\n const cache = cacheHitStats(input.cacheUsages);\n if (cache.requests > 0 && cache.session !== undefined && cache.last !== undefined) {\n lines.push(\"\");\n lines.push(\n `Prompt cache (provider-reported): ${formatHitRate(cache.last)} last · ${formatHitRate(cache.session)} session avg — ${fmt(cache.cacheRead)} of ${fmt(cache.billedPrompt)} billed prompt tokens served from cache (${cache.requests} req)`,\n );\n }\n }\n\n lines.push(\"\");\n\n if (nudge) {\n if (nudge.shouldInject) {\n const tierInfo = nudge.tier ? ` [T${nudge.tier} distillation]` : \"\";\n lines.push(`Nudge: ACTIVE${tierInfo} — ${nudge.reason}`);\n } else {\n lines.push(`Nudge: idle — ${nudge.reason}`);\n }\n }\n\n const ranges = viableRanges(nudge?.compressibleRanges ?? []);\n const protectedRanges = nudge?.protectedRanges ?? [];\n if (ranges.length > 0 || protectedRanges.length > 0) {\n lines.push(\"\");\n lines.push(formatRanges(ranges, protectedRanges));\n }\n\n if (activeBlocksList.length > 0) {\n lines.push(\"\");\n lines.push(`Blocks: ${activeBlocksList.length} active / ${totalBlocksList.length} total (${fmt(state.stats.tokensCompressed)} tokens compressed, cumulative)`);\n for (const b of activeBlocksList) {\n const topic = b.topic ? `: ${b.topic}` : `: ${topicFallback(b.summary || \"\")}`;\n const summaryTok = defaultCountTokens(b.summary || \"\");\n const origTok = b.compressedTokens > 0 ? b.compressedTokens : summaryTok;\n lines.push(` [${b.blockId}] T${b.tier} ${fmt(origTok)}→${fmt(summaryTok)}${topic}`);\n }\n } else if (totalBlocksList.length > 0) {\n lines.push(\"\");\n lines.push(`Blocks: 0 active / ${totalBlocksList.length} total (${fmt(state.stats.tokensCompressed)} tokens compressed, cumulative)`);\n } else {\n lines.push(\"\");\n lines.push(\"Blocks: none (nothing compressed yet)\");\n }\n\n lines.push(\"\");\n lines.push(\"Tag visibility: tags injected to LLM only (deep copy), not persisted in session, not shown in terminal.\");\n\n return lines.join(\"\\n\");\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../src/panel/topic.ts","../../src/panel/format.ts","../../src/panel/cache.ts","../../src/panel/panel.ts"],"sourcesContent":["/** Short topic for a block when the model did not provide one: first sentence\n * segment, leading quotes stripped, truncated to 30 chars with an ellipsis.\n * Used wherever block lists are rendered (panels, search results). */\nimport { clampPrefix } from \"../truncate.js\";\n\nexport function topicFallback(summary: string): string {\n const first = summary.split(/[.\\n]/)[0] ?? \"\";\n const t = first\n .trim()\n .replace(/^[\"'`]+/, \"\")\n .trim();\n return t.length <= 30 ? t : `${clampPrefix(t, 30).trimEnd()}…`;\n}\n","/** Compact token formatting for user-facing panels: lowercase k/M with the\n * same thresholds as the hosts' footers (<1000 → raw, <10000 → one decimal\n * k, <1e6 → rounded k, <1e7 → one decimal M). */\nexport function formatCompactTokens(count: number): string {\n if (count < 1000) return count.toString();\n if (count < 10000) return `${(count / 1000).toFixed(1)}k`;\n if (count < 1000000) return `${Math.round(count / 1000)}k`;\n if (count < 10000000) return `${(count / 1000000).toFixed(1)}M`;\n return `${Math.round(count / 1000000)}M`;\n}\n","/** Cache hit-rate math for the /acp status panel.\n *\n * Hosts feed per-request prompt-cache usage samples (from assistant\n * messages' provider-reported `usage`); the kernel derives the display\n * numbers. A request COUNTS only when the provider reported cache\n * activity for it (`cacheRead + cacheWrite > 0`): providers without\n * prompt-cache reporting (0/0 with plain `input`) must not drag the\n * average to a fabricated 0%. */\n\nexport interface CacheUsageSample {\n /** Non-cached conversation input tokens billed for the request. */\n input: number;\n /** Conversation tokens served from the prompt cache. */\n cacheRead: number;\n /** Conversation tokens written to the prompt cache (cache creation). */\n cacheWrite: number;\n}\n\nexport interface CacheHitSummary {\n /** Session hit rate (0..1), weighted by billed prompt tokens.\n * Undefined when no request reported cache activity. */\n session: number | undefined;\n /** Hit rate (0..1) of the most recent request that reported cache\n * activity. Undefined when no request reported any. */\n last: number | undefined;\n /** Counted requests (provider reported cache activity). */\n requests: number;\n /** Cumulative tokens served from cache. */\n cacheRead: number;\n /** Cumulative billed prompt tokens (input + cacheRead + cacheWrite). */\n billedPrompt: number;\n}\n\nfunction num(v: unknown): number {\n return typeof v === \"number\" && Number.isFinite(v) && v > 0 ? v : 0;\n}\n\n/** Aggregate per-request cache usage into panel display numbers. */\nexport function cacheHitStats(\n usages: readonly CacheUsageSample[],\n): CacheHitSummary {\n let cacheRead = 0;\n let billedPrompt = 0;\n let requests = 0;\n let last: number | undefined;\n for (const u of usages) {\n const read = num(u?.cacheRead);\n const write = num(u?.cacheWrite);\n const input = num(u?.input);\n // No cache signal on this request → excluded entirely (see header).\n if (read + write <= 0) continue;\n const total = read + write + input;\n if (total <= 0) continue;\n cacheRead += read;\n billedPrompt += total;\n requests += 1;\n last = read / total;\n }\n return {\n session: requests > 0 ? cacheRead / billedPrompt : undefined,\n last,\n requests,\n cacheRead,\n billedPrompt,\n };\n}\n\n/** Format a 0..1 rate as a percentage with one decimal (\"92.3%\"). */\nexport function formatHitRate(rate: number): string {\n return `${(Math.max(0, Math.min(1, rate)) * 100).toFixed(1)}%`;\n}\n","import { defaultCountTokens } from \"../tokenize.js\";\nimport { formatRanges } from \"../nudge-text.js\";\nimport type { CompressionState, NudgeDecision } from \"../types.js\";\nimport { formatCompactTokens } from \"./format.js\";\nimport { topicFallback } from \"./topic.js\";\nimport { viableRanges } from \"../viable.js\";\nimport {\n cacheHitStats,\n formatHitRate,\n type CacheUsageSample,\n} from \"./cache.js\";\n\nexport interface StatusPanelInput {\n /** Adapter identifier for the header, e.g. \"billion-context-omp@0.1.6\".\n * Omit to hide the version line. */\n version?: string;\n /** Host session accounting — the SAME number the host footer displays.\n * It includes compressed originals (summaries stay in the window), so it\n * shrinks slower than the sent view when compression prunes the\n * per-request projection. */\n tokenCount: number;\n /** Measured token count of the host system prompt (host-specific to\n * obtain; the kernel breakdown does not see it). */\n systemPromptTokens: number;\n /** Kernel state (blocks drive the Blocks section). */\n state: CompressionState;\n /** The nudge decision from core.processTurn for this turn, if any. The\n * panel applies the viability filter to compressibleRanges itself. */\n nudge: NudgeDecision | undefined;\n /** Configured model context window, in tokens. */\n modelContextLimit: number;\n /** Estimate of the FULL (unpruned) core-message projection, computed\n * with the SAME countTokens the core uses (kernel default = CJK-aware\n * defaultCountTokens) — the same estimation scale as the kernel\n * breakdown. When provided, the panel derives `Session-only` on that\n * scale (unpruned − sent). Without it the line is omitted: subtracting\n * the host's provider-scale number from an estimate-scale number\n * invents a third, meaningless scale (issue #18 \"看板统计的和拆分的有差异\"). */\n unprunedTokens?: number;\n /** Per-request prompt-cache usage (from assistant messages' provider-\n * reported `usage`). Requests without cache reporting are excluded by\n * cacheHitStats; when no counted request remains, the section is\n * omitted entirely. Omit the field to hide the section. */\n cacheUsages?: ReadonlyArray<CacheUsageSample>;\n /** Token formatter override (defaults to formatCompactTokens). */\n fmtTokens?: (n: number) => string;\n}\n\nfunction bar(value: number, total: number, width: number = 20): string {\n if (total === 0) return \"\";\n const filled = Math.max(\n 0,\n Math.min(width, Math.round((value / total) * width)),\n );\n return \"█\".repeat(filled) + \"░\".repeat(width - filled);\n}\n\n/** Render the /acp status panel. Three token numbers, each labeled with\n * its own scale, never mixed in arithmetic:\n * - Session accounting (host footer scale): the host's reported context\n * size INCLUDING compressed originals (summaries stay in the window), so\n * it shrinks slower than the sent view when compression prunes the\n * per-request projection.\n * - Sent view (estimated, kernel countTokens scale): what actually\n * reaches the LLM after compression (kernel's classification over the\n * pruned projection + measured system prompt). This is the number\n * compression controls.\n * - Session-only (estimated, kernel countTokens scale): unpruned\n * projection − sent view; the compressed originals pruned from every\n * request.\n * Subtracting the host number from an estimate produced numbers that\n * reconciled with neither scale (\"Framework 390K\", \"session-only 29k vs\n * 112k compressed\") — that is what issue #18 reported. */\nexport function buildStatusPanel(input: StatusPanelInput): string {\n const { tokenCount, state, nudge, modelContextLimit } = input;\n const fmt = input.fmtTokens ?? formatCompactTokens;\n const bd = nudge?.contextBreakdown;\n const limit = modelContextLimit;\n const classified = bd\n ? bd.system + bd.tool + bd.summaries + bd.code + bd.text\n : 0;\n const systemPromptTokens = input.systemPromptTokens;\n const sentTotal = classified + systemPromptTokens;\n // Same-scale derivation only: both sides use the core's countTokens\n // estimate (kernel default = CJK-aware defaultCountTokens). The host\n // footer's tokenCount (provider-anchored, session-tree) is displayed as\n // its own line and never fed into an arithmetic difference with these.\n const sessionOnly =\n input.unprunedTokens !== undefined\n ? Math.max(0, input.unprunedTokens - sentTotal)\n : 0;\n const displayTotal = tokenCount;\n const displayPct = limit > 0 ? Math.round((displayTotal / limit) * 100) : 0;\n const sentPct = limit > 0 ? Math.round((sentTotal / limit) * 100) : 0;\n const activeBlocksList = state.blocks.filter((b) => b.active);\n const totalBlocksList = state.blocks;\n\n const lines: string[] = [];\n\n lines.push(\"╭─────────────────────────────────────────────╮\");\n lines.push(\"│ ACP Context Analysis │\");\n lines.push(\"╰─────────────────────────────────────────────╯\");\n if (input.version) lines.push(input.version);\n lines.push(\"\");\n lines.push(\n `Context (session accounting, host footer scale): ${displayPct}% (${fmt(displayTotal)} / ${fmt(limit)}) — includes compressed originals; shrinks slower than the sent view`,\n );\n\n if (nudge && bd) {\n const growth = bd.growth;\n if (growth > 0 && displayTotal > 0) {\n lines.push(`Growth: +${fmt(growth)} since last nudge`);\n }\n lines.push(\"\");\n lines.push(\n `Sent to LLM (after compression, est.): ${fmt(sentTotal)}${limit > 0 ? ` (${sentPct}% of limit)` : \"\"}`,\n );\n if (input.unprunedTokens !== undefined && sessionOnly > 0) {\n lines.push(\n `Session-only (compressed originals, est.): ${fmt(sessionOnly)} — pruned from every request; the footer/nudge still count them`,\n );\n }\n lines.push(\"\");\n lines.push(\"Token Breakdown (sent view):\");\n\n const categories: Array<{ label: string; value: number }> = [\n { label: \"Tool\", value: bd.tool },\n { label: \"SysPrompt\", value: systemPromptTokens },\n { label: \"Text\", value: bd.text },\n { label: \"Code\", value: bd.code },\n { label: \"Summaries\", value: bd.summaries },\n ];\n\n for (const cat of categories) {\n if (cat.value <= 0) continue;\n const pct = sentTotal > 0 ? Math.round((cat.value / sentTotal) * 100) : 0;\n const b = bar(cat.value, sentTotal);\n lines.push(\n ` ${cat.label.padEnd(10)} ${b} ${String(pct).padStart(3)}% ${fmt(cat.value)}`,\n );\n }\n }\n\n if (input.cacheUsages) {\n const cache = cacheHitStats(input.cacheUsages);\n if (\n cache.requests > 0 &&\n cache.session !== undefined &&\n cache.last !== undefined\n ) {\n lines.push(\"\");\n lines.push(\n `Prompt cache (provider-reported): ${formatHitRate(cache.last)} last · ${formatHitRate(cache.session)} session avg — ${fmt(cache.cacheRead)} of ${fmt(cache.billedPrompt)} billed prompt tokens served from cache (${cache.requests} req)`,\n );\n }\n }\n\n lines.push(\"\");\n\n if (nudge) {\n if (nudge.shouldInject) {\n const tierInfo = nudge.tier ? ` [T${nudge.tier} distillation]` : \"\";\n lines.push(`Nudge: ACTIVE${tierInfo} — ${nudge.reason}`);\n } else {\n lines.push(`Nudge: idle — ${nudge.reason}`);\n }\n }\n\n const ranges = viableRanges(nudge?.compressibleRanges ?? []);\n const protectedRanges = nudge?.protectedRanges ?? [];\n if (ranges.length > 0 || protectedRanges.length > 0) {\n lines.push(\"\");\n lines.push(formatRanges(ranges, protectedRanges));\n }\n\n if (activeBlocksList.length > 0) {\n lines.push(\"\");\n lines.push(\n `Blocks: ${activeBlocksList.length} active / ${totalBlocksList.length} total (${fmt(state.stats.tokensCompressed)} tokens compressed, cumulative)`,\n );\n for (const b of activeBlocksList) {\n const topic = b.topic\n ? `: ${b.topic}`\n : `: ${topicFallback(b.summary || \"\")}`;\n const summaryTok = defaultCountTokens(b.summary || \"\");\n const origTok = b.compressedTokens > 0 ? b.compressedTokens : summaryTok;\n lines.push(\n ` [${b.blockId}] T${b.tier} ${fmt(origTok)}→${fmt(summaryTok)}${topic}`,\n );\n }\n } else if (totalBlocksList.length > 0) {\n lines.push(\"\");\n lines.push(\n `Blocks: 0 active / ${totalBlocksList.length} total (${fmt(state.stats.tokensCompressed)} tokens compressed, cumulative)`,\n );\n } else {\n lines.push(\"\");\n lines.push(\"Blocks: none (nothing compressed yet)\");\n }\n\n lines.push(\"\");\n lines.push(\n \"Tag visibility: tags injected to LLM only (deep copy), not persisted in session, not shown in terminal.\",\n );\n\n return lines.join(\"\\n\");\n}\n"],"mappings":"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","names":[]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"panel.d.ts","sourceRoot":"","sources":["../../src/panel/panel.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,gBAAgB,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAInE,OAAO,
|
|
1
|
+
{"version":3,"file":"panel.d.ts","sourceRoot":"","sources":["../../src/panel/panel.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,gBAAgB,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAInE,OAAO,EAGL,KAAK,gBAAgB,EACtB,MAAM,YAAY,CAAC;AAEpB,MAAM,WAAW,gBAAgB;IAC/B;yCACqC;IACrC,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB;;;kCAG8B;IAC9B,UAAU,EAAE,MAAM,CAAC;IACnB;yDACqD;IACrD,kBAAkB,EAAE,MAAM,CAAC;IAC3B,sDAAsD;IACtD,KAAK,EAAE,gBAAgB,CAAC;IACxB;2EACuE;IACvE,KAAK,EAAE,aAAa,GAAG,SAAS,CAAC;IACjC,kDAAkD;IAClD,iBAAiB,EAAE,MAAM,CAAC;IAC1B;;;;;;yEAMqE;IACrE,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB;;;gEAG4D;IAC5D,WAAW,CAAC,EAAE,aAAa,CAAC,gBAAgB,CAAC,CAAC;IAC9C,kEAAkE;IAClE,SAAS,CAAC,EAAE,CAAC,CAAC,EAAE,MAAM,KAAK,MAAM,CAAC;CACnC;AAWD;;;;;;;;;;;;;;;2DAe2D;AAC3D,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,gBAAgB,GAAG,MAAM,CAqIhE"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"topic.d.ts","sourceRoot":"","sources":["../../src/panel/topic.ts"],"names":[],"mappings":"AAKA,wBAAgB,aAAa,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,
|
|
1
|
+
{"version":3,"file":"topic.d.ts","sourceRoot":"","sources":["../../src/panel/topic.ts"],"names":[],"mappings":"AAKA,wBAAgB,aAAa,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAOrD"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"parse-compress-input.d.ts","sourceRoot":"","sources":["../src/parse-compress-input.ts"],"names":[],"mappings":"AAyBA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAEpD,MAAM,MAAM,iBAAiB,
|
|
1
|
+
{"version":3,"file":"parse-compress-input.d.ts","sourceRoot":"","sources":["../src/parse-compress-input.ts"],"names":[],"mappings":"AAyBA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAEpD,MAAM,MAAM,iBAAiB,GACzB,IAAI,GACJ,aAAa,GACb,YAAY,GACZ,iBAAiB,GACjB,mBAAmB,GACnB,gBAAgB,GAChB,WAAW,GACX,iBAAiB,CAAC;AAEtB,MAAM,WAAW,wBAAwB;IACvC,uDAAuD;IACvD,EAAE,EAAE,OAAO,CAAC;IACZ,2CAA2C;IAC3C,IAAI,EAAE,iBAAiB,CAAC;IACxB,wEAAwE;IACxE,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,oEAAoE;IACpE,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,oDAAoD;IACpD,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,iFAAiF;IACjF,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;IAChB,0DAA0D;IAC1D,YAAY,EAAE,MAAM,CAAC;IACrB,oEAAoE;IACpE,cAAc,CAAC,EAAE,MAAM,EAAE,CAAC;CAC3B;AAED,MAAM,WAAW,mBAAmB;IAClC,MAAM,EAAE,iBAAiB,EAAE,CAAC;IAC5B,WAAW,EAAE,wBAAwB,CAAC;CACvC;AAED;;;;;;;GAOG;AACH,wBAAgB,iBAAiB,CAC/B,KAAK,EAAE,OAAO,EACd,IAAI,CAAC,EAAE;IAAE,MAAM,CAAC,EAAE,MAAM,CAAA;CAAE,GACzB,mBAAmB,CAuBrB;AA0TD;;;0CAG0C;AAC1C,wBAAgB,sBAAsB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAS1E"}
|
package/dist/persist/index.d.ts
CHANGED
|
@@ -14,6 +14,6 @@
|
|
|
14
14
|
* - the store never deletes files; cleanup is a downstream decision
|
|
15
15
|
*/
|
|
16
16
|
export { StateStore, flatFileNameFor } from "./store.js";
|
|
17
|
-
export type { PersistedEnvelope, PersistLogger, StateStoreCodec, StateStoreOptions } from "./store.js";
|
|
17
|
+
export type { PersistedEnvelope, PersistLogger, StateStoreCodec, StateStoreOptions, } from "./store.js";
|
|
18
18
|
export { mergeCompressionState } from "./state-merge.js";
|
|
19
19
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/persist/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AACH,OAAO,EAAE,UAAU,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AACzD,YAAY,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/persist/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AACH,OAAO,EAAE,UAAU,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AACzD,YAAY,EACV,iBAAiB,EACjB,aAAa,EACb,eAAe,EACf,iBAAiB,GAClB,MAAM,YAAY,CAAC;AACpB,OAAO,EAAE,qBAAqB,EAAE,MAAM,kBAAkB,CAAC"}
|
package/dist/persist/index.js
CHANGED
|
@@ -121,7 +121,12 @@ var StateStore = class {
|
|
|
121
121
|
} catch {
|
|
122
122
|
}
|
|
123
123
|
if (!isTransientFsError(e) || attempt === this.retryAttempts - 1) break;
|
|
124
|
-
Atomics.wait(
|
|
124
|
+
Atomics.wait(
|
|
125
|
+
new Int32Array(new SharedArrayBuffer(4)),
|
|
126
|
+
0,
|
|
127
|
+
0,
|
|
128
|
+
this.backoffMs(attempt)
|
|
129
|
+
);
|
|
125
130
|
}
|
|
126
131
|
}
|
|
127
132
|
if (!lastErr) {
|
|
@@ -140,7 +145,12 @@ var StateStore = class {
|
|
|
140
145
|
spillPath = spill;
|
|
141
146
|
} catch (e) {
|
|
142
147
|
if (!isTransientFsError(e) || attempt === this.retryAttempts - 1) break;
|
|
143
|
-
Atomics.wait(
|
|
148
|
+
Atomics.wait(
|
|
149
|
+
new Int32Array(new SharedArrayBuffer(4)),
|
|
150
|
+
0,
|
|
151
|
+
0,
|
|
152
|
+
this.backoffMs(attempt)
|
|
153
|
+
);
|
|
144
154
|
}
|
|
145
155
|
}
|
|
146
156
|
if (spillPath) this.discovered.set(id, spillPath);
|
|
@@ -181,7 +191,9 @@ var StateStore = class {
|
|
|
181
191
|
const envelope = this.readEnvelope(file);
|
|
182
192
|
if (!envelope) continue;
|
|
183
193
|
const base = path.basename(file);
|
|
184
|
-
const relBase = path.basename(
|
|
194
|
+
const relBase = path.basename(
|
|
195
|
+
this.relPathOf(envelope.id, envelope.payload)
|
|
196
|
+
);
|
|
185
197
|
const flatBase = flatFileNameFor(envelope.id);
|
|
186
198
|
let owner = null;
|
|
187
199
|
if (base === relBase || base === flatBase) {
|
|
@@ -193,7 +205,10 @@ var StateStore = class {
|
|
|
193
205
|
}
|
|
194
206
|
}
|
|
195
207
|
if (owner === null) {
|
|
196
|
-
this.log(
|
|
208
|
+
this.log(
|
|
209
|
+
"warn",
|
|
210
|
+
`[persist] skipping ${rel(file, this.dir)}: filename does not match record id`
|
|
211
|
+
);
|
|
197
212
|
continue;
|
|
198
213
|
}
|
|
199
214
|
const existing = out.get(owner);
|
|
@@ -227,7 +242,10 @@ var StateStore = class {
|
|
|
227
242
|
await Promise.all(
|
|
228
243
|
[...builders.entries()].map(
|
|
229
244
|
([id, build]) => this.writeNow(id, build).catch((e) => {
|
|
230
|
-
this.log(
|
|
245
|
+
this.log(
|
|
246
|
+
"error",
|
|
247
|
+
`[persist] shutdown flush failed for ${id}: ${errText(e)}`
|
|
248
|
+
);
|
|
231
249
|
})
|
|
232
250
|
)
|
|
233
251
|
);
|
|
@@ -267,7 +285,8 @@ var StateStore = class {
|
|
|
267
285
|
lastErr = e;
|
|
268
286
|
await fsp.unlink(tmp).catch(() => {
|
|
269
287
|
});
|
|
270
|
-
if (!isTransientFsError(e) || attempt === this.retryAttempts - 1)
|
|
288
|
+
if (!isTransientFsError(e) || attempt === this.retryAttempts - 1)
|
|
289
|
+
break;
|
|
271
290
|
const { promise, resolve } = Promise.withResolvers();
|
|
272
291
|
setTimeout(resolve, this.backoffMs(attempt));
|
|
273
292
|
await promise;
|
|
@@ -331,7 +350,10 @@ var StateStore = class {
|
|
|
331
350
|
if (!custom) return flatFileNameFor(id);
|
|
332
351
|
const rel2 = path.normalize(custom);
|
|
333
352
|
if (path.isAbsolute(rel2) || rel2.split(/[\\/]+/).includes("..")) {
|
|
334
|
-
this.log(
|
|
353
|
+
this.log(
|
|
354
|
+
"warn",
|
|
355
|
+
`[persist] relPath for ${id} escapes dir; using flat name`
|
|
356
|
+
);
|
|
335
357
|
return flatFileNameFor(id);
|
|
336
358
|
}
|
|
337
359
|
return rel2;
|
|
@@ -340,7 +362,10 @@ var StateStore = class {
|
|
|
340
362
|
* rename is atomic). Prefixed `.tmp-` so loadAll skips orphans. */
|
|
341
363
|
tempPath(dest) {
|
|
342
364
|
const seq = this.tmpSeq++;
|
|
343
|
-
return path.join(
|
|
365
|
+
return path.join(
|
|
366
|
+
path.dirname(dest),
|
|
367
|
+
`.tmp-${path.basename(dest, ".json")}-${process.pid}-${seq}`
|
|
368
|
+
);
|
|
344
369
|
}
|
|
345
370
|
backoffMs(attempt) {
|
|
346
371
|
return Math.min(this.retryBaseMs * 2 ** attempt, this.retryMaxMs);
|
|
@@ -383,7 +408,10 @@ var StateStore = class {
|
|
|
383
408
|
const alertAt = count === 1 || count >= 2 && (count & count - 1) === 0;
|
|
384
409
|
if (!alertAt) return;
|
|
385
410
|
const where = spillPath ? `; data spilled to ${rel(spillPath, this.dir)}` : "; SPILLOVER ALSO FAILED \u2014 data at risk";
|
|
386
|
-
this.log(
|
|
411
|
+
this.log(
|
|
412
|
+
count === 1 ? "error" : "warn",
|
|
413
|
+
`[persist] write failed for ${id} (total ${count}x): ${errText(err)}${where}`
|
|
414
|
+
);
|
|
387
415
|
}
|
|
388
416
|
clearFailure(id) {
|
|
389
417
|
this.failCounts.delete(id);
|
|
@@ -398,20 +426,29 @@ var StateStore = class {
|
|
|
398
426
|
parsed = JSON.parse(text);
|
|
399
427
|
} catch (e) {
|
|
400
428
|
if (e.code !== "ENOENT") {
|
|
401
|
-
this.log(
|
|
429
|
+
this.log(
|
|
430
|
+
"warn",
|
|
431
|
+
`[persist] skipping corrupt file ${rel(file, this.dir)}: ${errText(e)}`
|
|
432
|
+
);
|
|
402
433
|
}
|
|
403
434
|
return null;
|
|
404
435
|
}
|
|
405
436
|
if (isEnvelopeLike(parsed)) {
|
|
406
437
|
if (!this.validateFn(parsed)) {
|
|
407
|
-
this.log(
|
|
438
|
+
this.log(
|
|
439
|
+
"warn",
|
|
440
|
+
`[persist] skipping invalid record ${rel(file, this.dir)}`
|
|
441
|
+
);
|
|
408
442
|
return null;
|
|
409
443
|
}
|
|
410
444
|
return parsed;
|
|
411
445
|
}
|
|
412
446
|
const adopted = this.adoptLegacy(parsed);
|
|
413
447
|
if (adopted) return adopted;
|
|
414
|
-
this.log(
|
|
448
|
+
this.log(
|
|
449
|
+
"warn",
|
|
450
|
+
`[persist] skipping invalid record ${rel(file, this.dir)}`
|
|
451
|
+
);
|
|
415
452
|
return null;
|
|
416
453
|
}
|
|
417
454
|
/** Wrap a legacy (pre-envelope) record as an envelope via the `legacy`
|