@gixcopilot/context 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (59) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +131 -0
  3. package/dist/context-compressor.d.ts +28 -0
  4. package/dist/context-compressor.d.ts.map +1 -0
  5. package/dist/context-compressor.js +35 -0
  6. package/dist/context-compressor.js.map +1 -0
  7. package/dist/context-engine.d.ts +36 -0
  8. package/dist/context-engine.d.ts.map +1 -0
  9. package/dist/context-engine.js +191 -0
  10. package/dist/context-engine.js.map +1 -0
  11. package/dist/context-format.d.ts +10 -0
  12. package/dist/context-format.d.ts.map +1 -0
  13. package/dist/context-format.js +16 -0
  14. package/dist/context-format.js.map +1 -0
  15. package/dist/context-item.d.ts +44 -0
  16. package/dist/context-item.d.ts.map +1 -0
  17. package/dist/context-item.js +2 -0
  18. package/dist/context-item.js.map +1 -0
  19. package/dist/context-priority.d.ts +13 -0
  20. package/dist/context-priority.d.ts.map +1 -0
  21. package/dist/context-priority.js +16 -0
  22. package/dist/context-priority.js.map +1 -0
  23. package/dist/context-registry.d.ts +47 -0
  24. package/dist/context-registry.d.ts.map +1 -0
  25. package/dist/context-registry.js +130 -0
  26. package/dist/context-registry.js.map +1 -0
  27. package/dist/context-scope.d.ts +19 -0
  28. package/dist/context-scope.d.ts.map +1 -0
  29. package/dist/context-scope.js +13 -0
  30. package/dist/context-scope.js.map +1 -0
  31. package/dist/context-sensitivity.d.ts +11 -0
  32. package/dist/context-sensitivity.d.ts.map +1 -0
  33. package/dist/context-sensitivity.js +11 -0
  34. package/dist/context-sensitivity.js.map +1 -0
  35. package/dist/context-serializer.d.ts +33 -0
  36. package/dist/context-serializer.d.ts.map +1 -0
  37. package/dist/context-serializer.js +112 -0
  38. package/dist/context-serializer.js.map +1 -0
  39. package/dist/index.d.ts +23 -0
  40. package/dist/index.d.ts.map +1 -0
  41. package/dist/index.js +11 -0
  42. package/dist/index.js.map +1 -0
  43. package/dist/resolved-context.d.ts +64 -0
  44. package/dist/resolved-context.d.ts.map +1 -0
  45. package/dist/resolved-context.js +2 -0
  46. package/dist/resolved-context.js.map +1 -0
  47. package/dist/state-patch.d.ts +35 -0
  48. package/dist/state-patch.d.ts.map +1 -0
  49. package/dist/state-patch.js +2 -0
  50. package/dist/state-patch.js.map +1 -0
  51. package/dist/state-store.d.ts +80 -0
  52. package/dist/state-store.d.ts.map +1 -0
  53. package/dist/state-store.js +129 -0
  54. package/dist/state-store.js.map +1 -0
  55. package/dist/token-estimator.d.ts +17 -0
  56. package/dist/token-estimator.d.ts.map +1 -0
  57. package/dist/token-estimator.js +16 -0
  58. package/dist/token-estimator.js.map +1 -0
  59. package/package.json +51 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 ahmed khaled
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,131 @@
1
+ # @gixcopilot/context
2
+
3
+ ## Purpose
4
+
5
+ ## Install
6
+
7
+ ```bash
8
+ npm install @gixcopilot/context
9
+ ```
10
+
11
+ Requires Node.js >=22.12.0. ESM only.
12
+
13
+ Framework-independent application context and shared state engine for the AI Copilot SDK
14
+ (Phase 4). Lets an application tell the Copilot what it is currently looking at - and gives
15
+ it a typed, subscribable place to keep shared state - without any dependency on React,
16
+ Angular, or a specific LLM provider.
17
+
18
+ ## Responsibilities
19
+
20
+ - `createContextRegistry()` — register/update/remove/list/subscribe application context
21
+ items, each scoped (`global`/`user`/`application`/`page`/`component`/`session`/
22
+ `temporary`), prioritized, and tagged with a sensitivity level.
23
+ - `createDefaultContextSerializer()` — the controlled boundary that turns an arbitrary
24
+ application value into safe, model-facing text (handles `undefined`, `Date`, `bigint`,
25
+ circular references, functions, DOM-like nodes, class instances, and oversized
26
+ strings/arrays deterministically, never by throwing or emitting invalid JSON).
27
+ - `createDefaultTokenEstimator()` — a dependency-free, provider-neutral token estimate.
28
+ - `createTruncatingCompressor()` — the deterministic default for the `ContextCompressor`
29
+ extension point (a foundation for future summarization, not built in Phase 4).
30
+ - `createContextEngine()` — the pipeline: collect → validate → serialize → filter
31
+ (enabled/sensitivity) → deduplicate → prioritize → budget/truncate → `ResolvedContext`,
32
+ plus `inspect()` for debugging what was included/excluded and why.
33
+ - `createCopilotStateStore()` — a small, typed, subscribable shared-state store. State is a
34
+ distinct concept from context (see "State vs Context" below) and is never automatically
35
+ exposed to a model. Extended in Phase 6 with a per-slot `revision`, an opt-in
36
+ `modelWritable` capability flag, and a validated, non-throwing `applyPatch()` pipeline
37
+ (`'applied' | 'conflict' | 'rejected'`) — see "AI-writable state" below.
38
+
39
+ ## Public API
40
+
41
+ See `src/index.ts`. No deep imports into `src/` are supported (the package's `exports`
42
+ field only exposes `.`).
43
+
44
+ ## Dependencies
45
+
46
+ - `@gixcopilot/protocol` — reused only for `CopilotError`, so context/state errors share the
47
+ SDK's one error taxonomy instead of inventing a parallel one.
48
+
49
+ ## Non-responsibilities
50
+
51
+ - **No React/Angular.** `@gixcopilot/react`'s `useCopilotContext`/`useCopilotState` are thin
52
+ adapters over this package (see `docs/adr/0009-context-and-state-architecture.md`).
53
+ - **No AI-based context selection.** Resolution is deterministic (scope/priority/budget),
54
+ not an extra LLM call to pick relevant context (Section 19 of the Phase 4 brief).
55
+ - **No security enforcement.** Sensitivity metadata and the default "exclude `restricted`"
56
+ policy are a foundation only - never an authorization mechanism. See the security skill
57
+ and Phase 7.
58
+ - **No durable memory.** `session`/`temporary` context and shared state are in-memory for
59
+ the life of the registry/store; nothing here persists across page loads or is Copilot
60
+ "memory" (a later phase's concern).
61
+
62
+ ## State vs Context
63
+
64
+ - **State** is mutable application/Copilot data (e.g. `applicationFilters`).
65
+ - **Context** is what has been selected/prepared for model consumption (e.g. "Current
66
+ filters are: status = pending").
67
+
68
+ State is not automatically sent to the model. Exposing a state value to a model is an
69
+ explicit, separate act — see `@gixcopilot/react`'s `useCopilotState({ exposeToModel })`.
70
+
71
+ ## Basic Usage
72
+
73
+ ```ts
74
+ import { createContextRegistry, createContextEngine } from '@gixcopilot/context';
75
+
76
+ const registry = createContextRegistry();
77
+ const engine = createContextEngine({ maxContextTokens: 4000 });
78
+
79
+ const registration = registry.register({
80
+ name: 'selectedApplication',
81
+ description: 'Application currently selected by the user',
82
+ scope: 'component',
83
+ priority: 'high',
84
+ value: { id: 'APP-1024', status: 'pending' },
85
+ });
86
+
87
+ const resolved = await engine.resolve(registry);
88
+ console.log(resolved.content); // ready to place into a model request
89
+
90
+ registration.update({ id: 'APP-1024', status: 'approved' });
91
+ registration.dispose();
92
+ ```
93
+
94
+ ```ts
95
+ import { createCopilotStateStore } from '@gixcopilot/context';
96
+
97
+ const state = createCopilotStateStore();
98
+ state.register({ id: 'filters', name: 'applicationFilters', initialValue: { status: 'all' } });
99
+ state.subscribe('filters', (value) => console.log('filters changed', value));
100
+ state.update('filters', (previous) => ({ ...previous, status: 'pending' }));
101
+ ```
102
+
103
+ ## AI-writable state (Phase 6)
104
+
105
+ A slot registered with `modelWritable: true` accepts a validated, revision-checked patch —
106
+ never a direct, untrusted write:
107
+
108
+ ```ts
109
+ state.register({ id: 'filters', name: 'applicationFilters', initialValue: { status: 'all' }, modelWritable: true });
110
+
111
+ const result = state.applyPatch('filters', { op: 'set', value: { status: 'pending' } }, state.getRevision('filters')!);
112
+ // { status: 'applied', revision: 1, value: { status: 'pending' } }
113
+ // | { status: 'conflict', currentRevision: number } <- baseRevision was stale
114
+ // | { status: 'rejected', reason: '...', detail?: string }
115
+ ```
116
+
117
+ `revision` increments on **every** successful `set`/`update`/`applyPatch`, so a UI-driven
118
+ change also invalidates a stale AI-proposed `baseRevision` — see
119
+ `docs/adr/0011-generative-ui-and-state-patch-architecture.md`. `@gixcopilot/generative-ui`
120
+ bridges a `modelWritable` slot into a reserved tool a model calls to propose a patch;
121
+ `@gixcopilot/react`'s `useCopilotState({ modelWritable: true })` wires this up automatically.
122
+
123
+ ## Documentation
124
+
125
+ - [context-and-state guide](https://github.com/AfoudaSWE/gix_ai_copilot_nx/blob/main/docs/guides/context-and-state.md)
126
+ - [Getting started](https://github.com/AfoudaSWE/gix_ai_copilot_nx/blob/main/docs/guides/getting-started.md)
127
+ - [Source](https://github.com/AfoudaSWE/gix_ai_copilot_nx/tree/main/packages/context)
128
+
129
+ ## License
130
+
131
+ MIT
@@ -0,0 +1,28 @@
1
+ import type { TokenEstimator } from './token-estimator.js';
2
+ /** The minimal shape a compressor operates on - already-serialized text plus its cost. */
3
+ export interface CompressibleText {
4
+ readonly text: string;
5
+ readonly estimatedTokens: number;
6
+ }
7
+ /**
8
+ * The compression extension point (Section 29). Phase 4 ships only a deterministic
9
+ * truncating implementation (`createTruncatingCompressor`); the interface is async-capable
10
+ * so a future phase can plug in an LLM-based summarizer for a single over-budget item
11
+ * without changing `ContextEngine`'s pipeline.
12
+ *
13
+ * Deliberately narrower than a whole-`SerializedContext` compressor: `ContextEngine`
14
+ * (`context-engine.ts`) already performs whole-context priority/budget selection itself
15
+ * (Section 23, 27) and only reaches for a compressor when one *individual* item's own text
16
+ * does not fit in whatever budget remains for it - see `Phase_4_Decisions.md`.
17
+ */
18
+ export interface ContextCompressor {
19
+ compress(input: CompressibleText, budgetTokens: number): Promise<CompressibleText> | CompressibleText;
20
+ }
21
+ /**
22
+ * Deterministically shrinks `text` toward `budgetTokens` using the supplied (or default)
23
+ * estimator, by iteratively resizing proportionally to the estimator's own ratio rather
24
+ * than assuming a fixed chars-per-token constant - keeps this correct for any pluggable
25
+ * estimator, not just the default heuristic.
26
+ */
27
+ export declare function createTruncatingCompressor(estimator?: TokenEstimator): ContextCompressor;
28
+ //# sourceMappingURL=context-compressor.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"context-compressor.d.ts","sourceRoot":"","sources":["../src/context-compressor.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAG3D,0FAA0F;AAC1F,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,eAAe,EAAE,MAAM,CAAC;CAClC;AAED;;;;;;;;;;GAUG;AACH,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,KAAK,EAAE,gBAAgB,EAAE,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,gBAAgB,CAAC,GAAG,gBAAgB,CAAC;CACvG;AAID;;;;;GAKG;AACH,wBAAgB,0BAA0B,CAAC,SAAS,GAAE,cAA8C,GAAG,iBAAiB,CA6BvH"}
@@ -0,0 +1,35 @@
1
+ import { createDefaultTokenEstimator } from './token-estimator.js';
2
+ const TRUNCATION_MARKER = '\n…(truncated to fit context budget)';
3
+ /**
4
+ * Deterministically shrinks `text` toward `budgetTokens` using the supplied (or default)
5
+ * estimator, by iteratively resizing proportionally to the estimator's own ratio rather
6
+ * than assuming a fixed chars-per-token constant - keeps this correct for any pluggable
7
+ * estimator, not just the default heuristic.
8
+ */
9
+ export function createTruncatingCompressor(estimator = createDefaultTokenEstimator()) {
10
+ return {
11
+ compress(input, budgetTokens) {
12
+ if (budgetTokens <= 0) {
13
+ return { text: '', estimatedTokens: 0 };
14
+ }
15
+ if (input.estimatedTokens <= budgetTokens) {
16
+ return input;
17
+ }
18
+ let text = input.text;
19
+ for (let attempt = 0; attempt < 6; attempt++) {
20
+ const currentTokens = estimator.estimate(text);
21
+ if (currentTokens <= budgetTokens) {
22
+ return { text, estimatedTokens: currentTokens };
23
+ }
24
+ const ratio = Math.max(0, budgetTokens / currentTokens);
25
+ const targetLength = Math.max(0, Math.floor(text.length * ratio) - TRUNCATION_MARKER.length);
26
+ if (targetLength <= 0) {
27
+ return { text: '', estimatedTokens: 0 };
28
+ }
29
+ text = text.slice(0, targetLength) + TRUNCATION_MARKER;
30
+ }
31
+ return { text, estimatedTokens: estimator.estimate(text) };
32
+ },
33
+ };
34
+ }
35
+ //# sourceMappingURL=context-compressor.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"context-compressor.js","sourceRoot":"","sources":["../src/context-compressor.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,2BAA2B,EAAE,MAAM,sBAAsB,CAAC;AAuBnE,MAAM,iBAAiB,GAAG,sCAAsC,CAAC;AAEjE;;;;;GAKG;AACH,MAAM,UAAU,0BAA0B,CAAC,YAA4B,2BAA2B,EAAE;IAClG,OAAO;QACL,QAAQ,CAAC,KAAuB,EAAE,YAAoB;YACpD,IAAI,YAAY,IAAI,CAAC,EAAE,CAAC;gBACtB,OAAO,EAAE,IAAI,EAAE,EAAE,EAAE,eAAe,EAAE,CAAC,EAAE,CAAC;YAC1C,CAAC;YACD,IAAI,KAAK,CAAC,eAAe,IAAI,YAAY,EAAE,CAAC;gBAC1C,OAAO,KAAK,CAAC;YACf,CAAC;YAED,IAAI,IAAI,GAAG,KAAK,CAAC,IAAI,CAAC;YACtB,KAAK,IAAI,OAAO,GAAG,CAAC,EAAE,OAAO,GAAG,CAAC,EAAE,OAAO,EAAE,EAAE,CAAC;gBAC7C,MAAM,aAAa,GAAG,SAAS,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;gBAC/C,IAAI,aAAa,IAAI,YAAY,EAAE,CAAC;oBAClC,OAAO,EAAE,IAAI,EAAE,eAAe,EAAE,aAAa,EAAE,CAAC;gBAClD,CAAC;gBACD,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,YAAY,GAAG,aAAa,CAAC,CAAC;gBACxD,MAAM,YAAY,GAAG,IAAI,CAAC,GAAG,CAC3B,CAAC,EACD,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,GAAG,KAAK,CAAC,GAAG,iBAAiB,CAAC,MAAM,CAC3D,CAAC;gBACF,IAAI,YAAY,IAAI,CAAC,EAAE,CAAC;oBACtB,OAAO,EAAE,IAAI,EAAE,EAAE,EAAE,eAAe,EAAE,CAAC,EAAE,CAAC;gBAC1C,CAAC;gBACD,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,YAAY,CAAC,GAAG,iBAAiB,CAAC;YACzD,CAAC;YACD,OAAO,EAAE,IAAI,EAAE,eAAe,EAAE,SAAS,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC;QAC7D,CAAC;KACF,CAAC;AACJ,CAAC"}
@@ -0,0 +1,36 @@
1
+ import type { ContextRegistry } from './context-registry.js';
2
+ import type { CopilotContextItem } from './context-item.js';
3
+ import type { ContextSerializer } from './context-serializer.js';
4
+ import type { TokenEstimator } from './token-estimator.js';
5
+ import type { ContextCompressor } from './context-compressor.js';
6
+ import type { ContextInspection, ResolvedContext } from './resolved-context.js';
7
+ export interface ContextEngineOptions {
8
+ /** Filters structured values before serialization or truncation. Throws fail closed per item. */
9
+ readonly dataPolicy?: {
10
+ redact(data: unknown): unknown;
11
+ };
12
+ /** Total token budget resolved context may consume. Default 8000 (Section 25). */
13
+ readonly maxContextTokens?: number;
14
+ readonly estimator?: TokenEstimator;
15
+ readonly serializer?: ContextSerializer;
16
+ readonly compressor?: ContextCompressor;
17
+ /**
18
+ * Returns `true` if an item is allowed to reach the model. Defaults to excluding
19
+ * `restricted` items. This is a conservative default, not a security boundary (Section 30,
20
+ * 58) - Phase 7 owns real sensitivity/PII enforcement.
21
+ */
22
+ readonly sensitivityPolicy?: (item: CopilotContextItem) => boolean;
23
+ }
24
+ /**
25
+ * The central pipeline: Registry -> Collect -> Validate -> Serialize -> Filter ->
26
+ * Deduplicate -> Prioritize -> Budget -> Resolved Context (Section 23). One registry's
27
+ * worth of items in, one `ResolvedContext` out - stateless with respect to the registry, so
28
+ * one engine can safely serve many isolated registries (Section 65).
29
+ */
30
+ export interface ContextEngine {
31
+ resolve(registry: ContextRegistry): Promise<ResolvedContext>;
32
+ /** Debug-friendly projection of `resolve()`, for future DevTools (Section 57, 90). */
33
+ inspect(registry: ContextRegistry): Promise<ContextInspection>;
34
+ }
35
+ export declare function createContextEngine(options?: ContextEngineOptions): ContextEngine;
36
+ //# sourceMappingURL=context-engine.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"context-engine.d.ts","sourceRoot":"","sources":["../src/context-engine.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAC7D,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AAE5D,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AAEjE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAE3D,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AAGjE,OAAO,KAAK,EAGV,iBAAiB,EACjB,eAAe,EAEhB,MAAM,uBAAuB,CAAC;AAM/B,MAAM,WAAW,oBAAoB;IACnC,iGAAiG;IACjG,QAAQ,CAAC,UAAU,CAAC,EAAE;QAAE,MAAM,CAAC,IAAI,EAAE,OAAO,GAAG,OAAO,CAAA;KAAE,CAAC;IACzD,kFAAkF;IAClF,QAAQ,CAAC,gBAAgB,CAAC,EAAE,MAAM,CAAC;IACnC,QAAQ,CAAC,SAAS,CAAC,EAAE,cAAc,CAAC;IACpC,QAAQ,CAAC,UAAU,CAAC,EAAE,iBAAiB,CAAC;IACxC,QAAQ,CAAC,UAAU,CAAC,EAAE,iBAAiB,CAAC;IACxC;;;;OAIG;IACH,QAAQ,CAAC,iBAAiB,CAAC,EAAE,CAAC,IAAI,EAAE,kBAAkB,KAAK,OAAO,CAAC;CACpE;AAED;;;;;GAKG;AACH,MAAM,WAAW,aAAa;IAC5B,OAAO,CAAC,QAAQ,EAAE,eAAe,GAAG,OAAO,CAAC,eAAe,CAAC,CAAC;IAC7D,sFAAsF;IACtF,OAAO,CAAC,QAAQ,EAAE,eAAe,GAAG,OAAO,CAAC,iBAAiB,CAAC,CAAC;CAChE;AAcD,wBAAgB,mBAAmB,CAAC,OAAO,GAAE,oBAAyB,GAAG,aAAa,CAmLrF"}
@@ -0,0 +1,191 @@
1
+ import { priorityWeight } from './context-priority.js';
2
+ import { createDefaultContextSerializer } from './context-serializer.js';
3
+ import { createDefaultTokenEstimator } from './token-estimator.js';
4
+ import { createTruncatingCompressor } from './context-compressor.js';
5
+ import { formatContextItemBlock, joinContextBlocks } from './context-format.js';
6
+ const DEFAULT_MAX_CONTEXT_TOKENS = 8000;
7
+ /** Smallest remaining budget the engine will bother compressing an item into (Section 28). */
8
+ const MIN_COMPRESSIBLE_BUDGET_TOKENS = 16;
9
+ function defaultSensitivityPolicy(item) {
10
+ return item.sensitivity !== 'restricted';
11
+ }
12
+ export function createContextEngine(options = {}) {
13
+ const maxContextTokens = options.maxContextTokens ?? DEFAULT_MAX_CONTEXT_TOKENS;
14
+ const estimator = options.estimator ?? createDefaultTokenEstimator();
15
+ const serializer = options.serializer ?? createDefaultContextSerializer();
16
+ const compressor = options.compressor ?? createTruncatingCompressor(estimator);
17
+ const sensitivityPolicy = options.sensitivityPolicy ?? defaultSensitivityPolicy;
18
+ async function resolve(registry) {
19
+ const startedAt = Date.now();
20
+ const allItems = registry.list();
21
+ const exclusions = [];
22
+ const candidates = [];
23
+ for (const item of allItems) {
24
+ // No runtime "invalid" check here: `ContextRegistry.register/update/patch` already
25
+ // reject a blank name at admission time, so every item reaching this loop is
26
+ // structurally valid. The `'invalid'` exclusion reason stays part of the type (Section
27
+ // 35) for a future validated-input path (e.g. schema-checked registration) rather than
28
+ // being exercised by dead code today - see Phase_4_Decisions.md.
29
+ if (!item.enabled) {
30
+ exclusions.push({ id: item.id, name: item.name, scope: item.scope, reason: 'disabled' });
31
+ continue;
32
+ }
33
+ if (!sensitivityPolicy(item)) {
34
+ exclusions.push({
35
+ id: item.id,
36
+ name: item.name,
37
+ scope: item.scope,
38
+ reason: 'sensitivity-policy',
39
+ });
40
+ continue;
41
+ }
42
+ try {
43
+ const serialized = serializer.serialize(options.dataPolicy ? options.dataPolicy.redact(item.value) : item.value);
44
+ const text = formatContextItemBlock(item.name, item.scope, item.description, serialized.text);
45
+ candidates.push({
46
+ item,
47
+ text,
48
+ estimatedTokens: estimator.estimate(text),
49
+ truncated: serialized.truncated,
50
+ dedupeKey: serialized.text,
51
+ });
52
+ }
53
+ catch (error) {
54
+ exclusions.push({
55
+ id: item.id,
56
+ name: item.name,
57
+ scope: item.scope,
58
+ reason: 'serialization-failure',
59
+ detail: error instanceof Error ? error.message : 'Unknown serialization error.',
60
+ });
61
+ }
62
+ }
63
+ // Deduplication (Section 24): identical serialized *values* collapse to the
64
+ // highest-priority (then earliest-registered) candidate; the rest are excluded as
65
+ // 'duplicate'. Comparing the serialized text is a deliberate identity/hash check, not a
66
+ // fuzzy similarity guess.
67
+ const bestByKey = new Map();
68
+ for (const candidate of candidates) {
69
+ const existing = bestByKey.get(candidate.dedupeKey);
70
+ if (!existing || priorityWeight(candidate.item.priority) < priorityWeight(existing.item.priority)) {
71
+ bestByKey.set(candidate.dedupeKey, candidate);
72
+ }
73
+ }
74
+ const deduped = [];
75
+ for (const candidate of candidates) {
76
+ if (bestByKey.get(candidate.dedupeKey) === candidate) {
77
+ deduped.push(candidate);
78
+ }
79
+ else {
80
+ exclusions.push({
81
+ id: candidate.item.id,
82
+ name: candidate.item.name,
83
+ scope: candidate.item.scope,
84
+ reason: 'duplicate',
85
+ });
86
+ }
87
+ }
88
+ // Prioritize (Section 20, 27): stable sort by explicit priority tier only.
89
+ const prioritized = deduped
90
+ .map((candidate, index) => ({ candidate, index }))
91
+ .sort((a, b) => {
92
+ const byPriority = priorityWeight(a.candidate.item.priority) - priorityWeight(b.candidate.item.priority);
93
+ return byPriority !== 0 ? byPriority : a.index - b.index;
94
+ })
95
+ .map((entry) => entry.candidate);
96
+ // Budget allocation with safe truncation (Section 27, 28): include while budget
97
+ // remains; an item that doesn't fit is compressed toward the remaining budget before
98
+ // being excluded outright.
99
+ const resolvedItems = [];
100
+ let remaining = maxContextTokens;
101
+ for (const candidate of prioritized) {
102
+ if (remaining <= 0) {
103
+ exclusions.push({
104
+ id: candidate.item.id,
105
+ name: candidate.item.name,
106
+ scope: candidate.item.scope,
107
+ reason: 'budget',
108
+ });
109
+ continue;
110
+ }
111
+ if (candidate.estimatedTokens <= remaining) {
112
+ resolvedItems.push(toResolvedItem(candidate));
113
+ remaining -= candidate.estimatedTokens;
114
+ continue;
115
+ }
116
+ // Below this, compressing would only produce a near-useless fragment - exclude
117
+ // outright instead of "including" a scrap of text (Section 28). Only a remaining
118
+ // budget worth compressing into is worth spending the compressor call on.
119
+ if (remaining < MIN_COMPRESSIBLE_BUDGET_TOKENS) {
120
+ exclusions.push({
121
+ id: candidate.item.id,
122
+ name: candidate.item.name,
123
+ scope: candidate.item.scope,
124
+ reason: 'budget',
125
+ });
126
+ continue;
127
+ }
128
+ const compressed = await compressor.compress({ text: candidate.text, estimatedTokens: candidate.estimatedTokens }, remaining);
129
+ if (compressed.estimatedTokens > 0 && compressed.estimatedTokens <= remaining) {
130
+ resolvedItems.push(toResolvedItem({ ...candidate, text: compressed.text, estimatedTokens: compressed.estimatedTokens, truncated: true }));
131
+ remaining -= compressed.estimatedTokens;
132
+ }
133
+ else {
134
+ exclusions.push({
135
+ id: candidate.item.id,
136
+ name: candidate.item.name,
137
+ scope: candidate.item.scope,
138
+ reason: 'budget',
139
+ });
140
+ }
141
+ }
142
+ const content = joinContextBlocks(resolvedItems.map((item) => item.text));
143
+ const diagnostics = {
144
+ itemsRegistered: allItems.length,
145
+ itemsIncluded: resolvedItems.length,
146
+ itemsExcluded: exclusions.length,
147
+ resolutionMs: Date.now() - startedAt,
148
+ };
149
+ return {
150
+ items: resolvedItems,
151
+ content,
152
+ estimatedTokens: content ? estimator.estimate(content) : 0,
153
+ excluded: exclusions,
154
+ diagnostics,
155
+ };
156
+ }
157
+ async function inspect(registry) {
158
+ const resolved = await resolve(registry);
159
+ return {
160
+ estimatedTokens: resolved.estimatedTokens,
161
+ included: resolved.items.map((item) => ({
162
+ name: item.name,
163
+ scope: item.scope,
164
+ priority: item.priority,
165
+ estimatedTokens: item.estimatedTokens,
166
+ truncated: item.truncated,
167
+ })),
168
+ excluded: resolved.excluded.map((exclusion) => ({
169
+ name: exclusion.name,
170
+ scope: exclusion.scope,
171
+ reason: exclusion.reason,
172
+ })),
173
+ diagnostics: resolved.diagnostics,
174
+ };
175
+ }
176
+ return { resolve, inspect };
177
+ }
178
+ function toResolvedItem(candidate) {
179
+ return {
180
+ id: candidate.item.id,
181
+ name: candidate.item.name,
182
+ description: candidate.item.description,
183
+ scope: candidate.item.scope,
184
+ priority: candidate.item.priority,
185
+ sensitivity: candidate.item.sensitivity,
186
+ estimatedTokens: candidate.estimatedTokens,
187
+ truncated: candidate.truncated,
188
+ text: candidate.text,
189
+ };
190
+ }
191
+ //# sourceMappingURL=context-engine.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"context-engine.js","sourceRoot":"","sources":["../src/context-engine.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,10 @@
1
+ import type { ContextScope } from './context-scope.js';
2
+ /**
3
+ * Renders one item's stable, structured, model-facing block (Section 22). This is the only
4
+ * place prompt text is assembled for a context item - application code registers structured
5
+ * data; it never hand-formats a prompt string itself (see the context-engine skill).
6
+ */
7
+ export declare function formatContextItemBlock(name: string, scope: ContextScope, description: string | undefined, serializedText: string): string;
8
+ /** Joins already-formatted item blocks into the single content string sent with a run. */
9
+ export declare function joinContextBlocks(blocks: readonly string[]): string;
10
+ //# sourceMappingURL=context-format.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"context-format.d.ts","sourceRoot":"","sources":["../src/context-format.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAEvD;;;;GAIG;AACH,wBAAgB,sBAAsB,CACpC,IAAI,EAAE,MAAM,EACZ,KAAK,EAAE,YAAY,EACnB,WAAW,EAAE,MAAM,GAAG,SAAS,EAC/B,cAAc,EAAE,MAAM,GACrB,MAAM,CAIR;AAED,0FAA0F;AAC1F,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,SAAS,MAAM,EAAE,GAAG,MAAM,CAEnE"}
@@ -0,0 +1,16 @@
1
+ /**
2
+ * Renders one item's stable, structured, model-facing block (Section 22). This is the only
3
+ * place prompt text is assembled for a context item - application code registers structured
4
+ * data; it never hand-formats a prompt string itself (see the context-engine skill).
5
+ */
6
+ export function formatContextItemBlock(name, scope, description, serializedText) {
7
+ const lines = [`[Context: ${name}]`, `Scope: ${scope}`];
8
+ if (description)
9
+ lines.push(`Description: ${description}`);
10
+ return `${lines.join('\n')}\n\n${serializedText}`;
11
+ }
12
+ /** Joins already-formatted item blocks into the single content string sent with a run. */
13
+ export function joinContextBlocks(blocks) {
14
+ return blocks.join('\n\n---\n\n');
15
+ }
16
+ //# sourceMappingURL=context-format.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"context-format.js","sourceRoot":"","sources":["../src/context-format.ts"],"names":[],"mappings":"AAEA;;;;GAIG;AACH,MAAM,UAAU,sBAAsB,CACpC,IAAY,EACZ,KAAmB,EACnB,WAA+B,EAC/B,cAAsB;IAEtB,MAAM,KAAK,GAAG,CAAC,aAAa,IAAI,GAAG,EAAE,UAAU,KAAK,EAAE,CAAC,CAAC;IACxD,IAAI,WAAW;QAAE,KAAK,CAAC,IAAI,CAAC,gBAAgB,WAAW,EAAE,CAAC,CAAC;IAC3D,OAAO,GAAG,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,cAAc,EAAE,CAAC;AACpD,CAAC;AAED,0FAA0F;AAC1F,MAAM,UAAU,iBAAiB,CAAC,MAAyB;IACzD,OAAO,MAAM,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC;AACpC,CAAC"}
@@ -0,0 +1,44 @@
1
+ import type { ContextPriority } from './context-priority.js';
2
+ import type { ContextScope } from './context-scope.js';
3
+ import type { ContextSensitivity } from './context-sensitivity.js';
4
+ /** Free-form, serializable metadata a caller can attach for debugging (Section 34). */
5
+ export type ContextItemMetadata = Readonly<Record<string, unknown>>;
6
+ /**
7
+ * A framework-independent, transport-ready context item (Section 7). `value` is arbitrary
8
+ * application data at registration time; it only becomes model-facing text after passing
9
+ * through the engine's serializer (`context-serializer.ts`) - registering an item never
10
+ * hands a raw object to a model.
11
+ */
12
+ export interface CopilotContextItem<T = unknown> {
13
+ readonly id: string;
14
+ readonly name: string;
15
+ readonly description?: string;
16
+ readonly scope: ContextScope;
17
+ readonly value: T;
18
+ readonly priority: ContextPriority;
19
+ readonly sensitivity: ContextSensitivity;
20
+ /** Disabled items are stored but never reach `ContextEngine.resolve()` (Section 31). */
21
+ readonly enabled: boolean;
22
+ /** Free-form origin label (e.g. `'react-component'`) - never a framework object (Section 39). */
23
+ readonly owner?: string;
24
+ readonly metadata?: ContextItemMetadata;
25
+ }
26
+ /**
27
+ * What a caller passes to `ContextRegistry.register()`. `id` is optional - see
28
+ * `context-registry.ts` for the identity/deduplication rule (Section 18) it triggers.
29
+ */
30
+ export interface ContextItemInput<T = unknown> {
31
+ readonly id?: string;
32
+ readonly name: string;
33
+ readonly description?: string;
34
+ readonly scope: ContextScope;
35
+ readonly value: T;
36
+ readonly priority?: ContextPriority;
37
+ readonly sensitivity?: ContextSensitivity;
38
+ readonly enabled?: boolean;
39
+ readonly owner?: string;
40
+ readonly metadata?: ContextItemMetadata;
41
+ }
42
+ /** A partial update applied in place by `ContextRegistration.update()` (Section 17, 38). */
43
+ export type ContextItemPatch<T = unknown> = Partial<Omit<ContextItemInput<T>, 'id'>>;
44
+ //# sourceMappingURL=context-item.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"context-item.d.ts","sourceRoot":"","sources":["../src/context-item.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAC7D,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AACvD,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,0BAA0B,CAAC;AAEnE,uFAAuF;AACvF,MAAM,MAAM,mBAAmB,GAAG,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;AAEpE;;;;;GAKG;AACH,MAAM,WAAW,kBAAkB,CAAC,CAAC,GAAG,OAAO;IAC7C,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,KAAK,EAAE,YAAY,CAAC;IAC7B,QAAQ,CAAC,KAAK,EAAE,CAAC,CAAC;IAClB,QAAQ,CAAC,QAAQ,EAAE,eAAe,CAAC;IACnC,QAAQ,CAAC,WAAW,EAAE,kBAAkB,CAAC;IACzC,wFAAwF;IACxF,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;IAC1B,iGAAiG;IACjG,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,QAAQ,CAAC,EAAE,mBAAmB,CAAC;CACzC;AAED;;;GAGG;AACH,MAAM,WAAW,gBAAgB,CAAC,CAAC,GAAG,OAAO;IAC3C,QAAQ,CAAC,EAAE,CAAC,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,KAAK,EAAE,YAAY,CAAC;IAC7B,QAAQ,CAAC,KAAK,EAAE,CAAC,CAAC;IAClB,QAAQ,CAAC,QAAQ,CAAC,EAAE,eAAe,CAAC;IACpC,QAAQ,CAAC,WAAW,CAAC,EAAE,kBAAkB,CAAC;IAC1C,QAAQ,CAAC,OAAO,CAAC,EAAE,OAAO,CAAC;IAC3B,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,QAAQ,CAAC,EAAE,mBAAmB,CAAC;CACzC;AAED,4FAA4F;AAC5F,MAAM,MAAM,gBAAgB,CAAC,CAAC,GAAG,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC,gBAAgB,CAAC,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC,CAAC"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=context-item.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"context-item.js","sourceRoot":"","sources":["../src/context-item.ts"],"names":[],"mappings":""}
@@ -0,0 +1,13 @@
1
+ /**
2
+ * Explicit context priority (Section 20). A closed set of four tiers, not a numeric scale -
3
+ * numeric priority invites meaningless fine-grained comparisons ("47 vs 48") with no
4
+ * documented semantics. Priority affects budget selection only; it is never a security
5
+ * boundary (see Section 20 and the security skill).
6
+ */
7
+ export type ContextPriority = 'critical' | 'high' | 'normal' | 'low';
8
+ export declare const CONTEXT_PRIORITIES: readonly ContextPriority[];
9
+ export declare const DEFAULT_CONTEXT_PRIORITY: ContextPriority;
10
+ /** Lower is more important. Used to sort items before budget allocation (Section 27). */
11
+ export declare function priorityWeight(priority: ContextPriority): number;
12
+ export declare function isContextPriority(value: unknown): value is ContextPriority;
13
+ //# sourceMappingURL=context-priority.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"context-priority.d.ts","sourceRoot":"","sources":["../src/context-priority.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,MAAM,MAAM,eAAe,GAAG,UAAU,GAAG,MAAM,GAAG,QAAQ,GAAG,KAAK,CAAC;AAErE,eAAO,MAAM,kBAAkB,EAAE,SAAS,eAAe,EAA0C,CAAC;AAEpG,eAAO,MAAM,wBAAwB,EAAE,eAA0B,CAAC;AASlE,yFAAyF;AACzF,wBAAgB,cAAc,CAAC,QAAQ,EAAE,eAAe,GAAG,MAAM,CAEhE;AAED,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,eAAe,CAE1E"}
@@ -0,0 +1,16 @@
1
+ export const CONTEXT_PRIORITIES = ['critical', 'high', 'normal', 'low'];
2
+ export const DEFAULT_CONTEXT_PRIORITY = 'normal';
3
+ const PRIORITY_WEIGHT = {
4
+ critical: 0,
5
+ high: 1,
6
+ normal: 2,
7
+ low: 3,
8
+ };
9
+ /** Lower is more important. Used to sort items before budget allocation (Section 27). */
10
+ export function priorityWeight(priority) {
11
+ return PRIORITY_WEIGHT[priority];
12
+ }
13
+ export function isContextPriority(value) {
14
+ return typeof value === 'string' && CONTEXT_PRIORITIES.includes(value);
15
+ }
16
+ //# sourceMappingURL=context-priority.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"context-priority.js","sourceRoot":"","sources":["../src/context-priority.ts"],"names":[],"mappings":"AAQA,MAAM,CAAC,MAAM,kBAAkB,GAA+B,CAAC,UAAU,EAAE,MAAM,EAAE,QAAQ,EAAE,KAAK,CAAC,CAAC;AAEpG,MAAM,CAAC,MAAM,wBAAwB,GAAoB,QAAQ,CAAC;AAElE,MAAM,eAAe,GAA8C;IACjE,QAAQ,EAAE,CAAC;IACX,IAAI,EAAE,CAAC;IACP,MAAM,EAAE,CAAC;IACT,GAAG,EAAE,CAAC;CACP,CAAC;AAEF,yFAAyF;AACzF,MAAM,UAAU,cAAc,CAAC,QAAyB;IACtD,OAAO,eAAe,CAAC,QAAQ,CAAC,CAAC;AACnC,CAAC;AAED,MAAM,UAAU,iBAAiB,CAAC,KAAc;IAC9C,OAAO,OAAO,KAAK,KAAK,QAAQ,IAAK,kBAAwC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;AAChG,CAAC"}