@oscharko-dev/keiko-workflows 0.2.6 → 0.2.8

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 (53) hide show
  1. package/dist/.tsbuildinfo +1 -1
  2. package/dist/context-budget/allocator.d.ts +29 -0
  3. package/dist/context-budget/allocator.d.ts.map +1 -0
  4. package/dist/context-budget/allocator.js +185 -0
  5. package/dist/context-budget/compaction-helpers.d.ts +44 -0
  6. package/dist/context-budget/compaction-helpers.d.ts.map +1 -0
  7. package/dist/context-budget/compaction-helpers.js +203 -0
  8. package/dist/context-budget/compaction.d.ts +14 -0
  9. package/dist/context-budget/compaction.d.ts.map +1 -0
  10. package/dist/context-budget/compaction.js +97 -0
  11. package/dist/context-budget/defaults.d.ts +3 -0
  12. package/dist/context-budget/defaults.d.ts.map +1 -0
  13. package/dist/context-budget/defaults.js +75 -0
  14. package/dist/context-budget/index.d.ts +8 -0
  15. package/dist/context-budget/index.d.ts.map +1 -0
  16. package/dist/context-budget/index.js +6 -0
  17. package/dist/context-budget/rehydration.d.ts +11 -0
  18. package/dist/context-budget/rehydration.d.ts.map +1 -0
  19. package/dist/context-budget/rehydration.js +76 -0
  20. package/dist/contextpack/assemble.d.ts +2 -1
  21. package/dist/contextpack/assemble.d.ts.map +1 -1
  22. package/dist/contextpack/assemble.js +19 -0
  23. package/dist/index.d.ts +2 -0
  24. package/dist/index.d.ts.map +1 -1
  25. package/dist/index.js +4 -0
  26. package/dist/observations/command.d.ts +6 -0
  27. package/dist/observations/command.d.ts.map +1 -0
  28. package/dist/observations/command.js +67 -0
  29. package/dist/observations/index.d.ts +5 -0
  30. package/dist/observations/index.d.ts.map +1 -0
  31. package/dist/observations/index.js +6 -0
  32. package/dist/observations/search.d.ts +9 -0
  33. package/dist/observations/search.d.ts.map +1 -0
  34. package/dist/observations/search.js +43 -0
  35. package/dist/observations/shared.d.ts +18 -0
  36. package/dist/observations/shared.d.ts.map +1 -0
  37. package/dist/observations/shared.js +63 -0
  38. package/dist/observations/test.d.ts +6 -0
  39. package/dist/observations/test.d.ts.map +1 -0
  40. package/dist/observations/test.js +47 -0
  41. package/dist/planner/anchors.d.ts.map +1 -1
  42. package/dist/planner/anchors.js +3 -1
  43. package/dist/planner/intent.d.ts.map +1 -1
  44. package/dist/planner/intent.js +6 -0
  45. package/dist/ranking/rank.d.ts.map +1 -1
  46. package/dist/ranking/rank.js +5 -3
  47. package/dist/ranking/scoring.d.ts +4 -0
  48. package/dist/ranking/scoring.d.ts.map +1 -1
  49. package/dist/ranking/scoring.js +29 -1
  50. package/dist/ranking/signals.d.ts +5 -1
  51. package/dist/ranking/signals.d.ts.map +1 -1
  52. package/dist/ranking/signals.js +23 -3
  53. package/package.json +10 -10
@@ -0,0 +1,8 @@
1
+ export type { AllocateContextInput, AllocateContextResult, AllocatedContextLane, ContextLaneInput, ContextLaneItemInput, } from "./allocator.js";
2
+ export { allocateContext } from "./allocator.js";
3
+ export { DEFAULT_CONTEXT_BUDGET } from "./defaults.js";
4
+ export type { BuildCompactionInput, CompactionDigest } from "./compaction.js";
5
+ export { buildCompactionRecords } from "./compaction.js";
6
+ export type { RehydrationResult } from "./rehydration.js";
7
+ export { rehydrateProvenanceRef, rehydrateHandle } from "./rehydration.js";
8
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/context-budget/index.ts"],"names":[],"mappings":"AAGA,YAAY,EACV,oBAAoB,EACpB,qBAAqB,EACrB,oBAAoB,EACpB,gBAAgB,EAChB,oBAAoB,GACrB,MAAM,gBAAgB,CAAC;AACxB,OAAO,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AAEjD,OAAO,EAAE,sBAAsB,EAAE,MAAM,eAAe,CAAC;AAEvD,YAAY,EAAE,oBAAoB,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AAC9E,OAAO,EAAE,sBAAsB,EAAE,MAAM,iBAAiB,CAAC;AAEzD,YAAY,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AAC1D,OAAO,EAAE,sBAAsB,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC"}
@@ -0,0 +1,6 @@
1
+ // Public sub-barrel for the deterministic context-budget allocator (ADR-0052 D6). External
2
+ // consumers import the allocator surface and the default budget plan through this module.
3
+ export { allocateContext } from "./allocator.js";
4
+ export { DEFAULT_CONTEXT_BUDGET } from "./defaults.js";
5
+ export { buildCompactionRecords } from "./compaction.js";
6
+ export { rehydrateProvenanceRef, rehydrateHandle } from "./rehydration.js";
@@ -0,0 +1,11 @@
1
+ import type { ContextProvenanceRef, ContextRehydrationHandle } from "@oscharko-dev/keiko-contracts";
2
+ import { type SearchScope, type WorkspaceFs } from "@oscharko-dev/keiko-workspace";
3
+ export interface RehydrationResult {
4
+ readonly resolved: boolean;
5
+ readonly invalidated?: boolean | undefined;
6
+ readonly content?: string | undefined;
7
+ readonly reason?: string | undefined;
8
+ }
9
+ export declare function rehydrateProvenanceRef(ref: ContextProvenanceRef, scope: SearchScope, fs: WorkspaceFs, maxBytes?: number): Promise<RehydrationResult>;
10
+ export declare function rehydrateHandle(handle: ContextRehydrationHandle, scope: SearchScope, fs: WorkspaceFs, maxBytes?: number): Promise<RehydrationResult>;
11
+ //# sourceMappingURL=rehydration.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rehydration.d.ts","sourceRoot":"","sources":["../../src/context-budget/rehydration.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,oBAAoB,EAAE,wBAAwB,EAAE,MAAM,+BAA+B,CAAC;AACpG,OAAO,EAGL,KAAK,WAAW,EAChB,KAAK,WAAW,EACjB,MAAM,+BAA+B,CAAC;AAEvC,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAC;IAC3B,QAAQ,CAAC,WAAW,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IAC3C,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACtC,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CACtC;AAuDD,wBAAsB,sBAAsB,CAC1C,GAAG,EAAE,oBAAoB,EACzB,KAAK,EAAE,WAAW,EAClB,EAAE,EAAE,WAAW,EACf,QAAQ,CAAC,EAAE,MAAM,GAChB,OAAO,CAAC,iBAAiB,CAAC,CAuB5B;AAKD,wBAAsB,eAAe,CACnC,MAAM,EAAE,wBAAwB,EAChC,KAAK,EAAE,WAAW,EAClB,EAAE,EAAE,WAAW,EACf,QAAQ,CAAC,EAAE,MAAM,GAChB,OAAO,CAAC,iBAAiB,CAAC,CAa5B"}
@@ -0,0 +1,76 @@
1
+ // Bounded, deny-checked, observable rehydration of compacted provenance (ADR-0053 D5). The ONLY IO
2
+ // path in the context-budget module: every repo-file read goes through readExcerpt, which itself
3
+ // runs isDenied + containment + binary/size gates and throws on a denied/binary/too-large path. We
4
+ // CATCH those throws and degrade to {resolved:false, reason} so a stale or denied source never
5
+ // crashes the caller. The excerpt-content hash is recomputed on read so a line-range change is
6
+ // detected precisely against the handle's contentHash.
7
+ import { hashExcerptContent, readExcerpt, } from "@oscharko-dev/keiko-workspace";
8
+ // Independent of whatever the caller passes: rehydration is always bounded. 256 KiB is generous for
9
+ // a single excerpt window yet far under readExcerpt's 2 MiB file cap. A caller passing Infinity or
10
+ // an oversized value cannot widen this — Math.min clamps it.
11
+ const DEFAULT_REHYDRATION_MAX_BYTES = 262_144;
12
+ const MAX_REHYDRATION_MAX_BYTES = 2_097_152;
13
+ function boundMaxBytes(maxBytes) {
14
+ const requested = maxBytes !== undefined && Number.isFinite(maxBytes) && maxBytes >= 0
15
+ ? Math.floor(maxBytes)
16
+ : DEFAULT_REHYDRATION_MAX_BYTES;
17
+ return Math.min(requested, MAX_REHYDRATION_MAX_BYTES);
18
+ }
19
+ function deferred(kind) {
20
+ return { resolved: false, reason: `kind ${kind} rehydration deferred (PR3/PR4)` };
21
+ }
22
+ async function readRepoFile(target, scope, fs, maxBytes) {
23
+ try {
24
+ const result = await readExcerpt(scope, {
25
+ scopePath: target.scopePath,
26
+ startLine: target.startLine,
27
+ endLine: target.endLine,
28
+ maxBytes: boundMaxBytes(maxBytes),
29
+ }, { fs });
30
+ const newHash = hashExcerptContent(result.content);
31
+ const invalidated = target.contentHash !== undefined && newHash !== target.contentHash;
32
+ return { resolved: true, invalidated, content: result.content };
33
+ }
34
+ catch (error) {
35
+ return { resolved: false, reason: error instanceof Error ? error.message : String(error) };
36
+ }
37
+ }
38
+ // Resolves a single ContextProvenanceRef. A notPersistedReason short-circuits WITHOUT any read.
39
+ // kind 'repo-file' with scopePath + lineRange reads via readExcerpt (deny/bounds gated). All other
40
+ // kinds are deferred to a later PR with no IO.
41
+ export async function rehydrateProvenanceRef(ref, scope, fs, maxBytes) {
42
+ if (ref.notPersistedReason !== undefined) {
43
+ return { resolved: false, reason: ref.notPersistedReason };
44
+ }
45
+ if (ref.kind !== "repo-file") {
46
+ return deferred(ref.kind);
47
+ }
48
+ const scopePath = ref.scopePath;
49
+ const lineRange = ref.lineRange;
50
+ if (scopePath === undefined || lineRange === undefined) {
51
+ return { resolved: false, reason: "repo-file ref missing scopePath or lineRange" };
52
+ }
53
+ return readRepoFile({
54
+ scopePath,
55
+ startLine: lineRange.startLine,
56
+ endLine: lineRange.endLine,
57
+ contentHash: ref.contentHash,
58
+ }, scope, fs, maxBytes);
59
+ }
60
+ // Resolves a lane-level handle. A handle that carries kind + scopePath + lineRange is resolved by
61
+ // constructing the equivalent repo-file ref; otherwise it is lane-level (an opaque eviction-set
62
+ // pointer) and not directly rehydratable.
63
+ export async function rehydrateHandle(handle, scope, fs, maxBytes) {
64
+ const { kind, scopePath, lineRange } = handle;
65
+ if (kind === undefined || scopePath === undefined || lineRange === undefined) {
66
+ return { resolved: false, reason: "handle not directly rehydratable (lane-level)" };
67
+ }
68
+ const ref = {
69
+ kind,
70
+ stableId: handle.handleId,
71
+ scopePath,
72
+ lineRange,
73
+ ...(handle.contentHash !== undefined ? { contentHash: handle.contentHash } : {}),
74
+ };
75
+ return rehydrateProvenanceRef(ref, scope, fs, maxBytes);
76
+ }
@@ -1,4 +1,4 @@
1
- import { type CandidateFile, type ConnectedContextPack, type EvidenceAtom, type ExplorationBudget, type ExplorationUsage, type OmittedContextEntry, type RetrievalQuery, type SelectedScope, type UncertaintyMarker } from "@oscharko-dev/keiko-contracts/connected-context";
1
+ import { type CandidateFile, type ConnectedContextPack, type ContextPackDiagnostics, type EvidenceAtom, type ExplorationBudget, type ExplorationUsage, type OmittedContextEntry, type RetrievalQuery, type SelectedScope, type UncertaintyMarker } from "@oscharko-dev/keiko-contracts/connected-context";
2
2
  import { type MicroIndex } from "./microIndex.js";
3
3
  import { type RerankerSeam } from "./reranker.js";
4
4
  export interface AssembleInput {
@@ -12,6 +12,7 @@ export interface AssembleInput {
12
12
  readonly cacheIdentity?: readonly string[] | undefined;
13
13
  readonly initialUsage?: ExplorationUsage;
14
14
  readonly initialUncertainty?: readonly UncertaintyMarker[];
15
+ readonly diagnostics?: ContextPackDiagnostics | undefined;
15
16
  }
16
17
  export interface ExcerptWindow {
17
18
  readonly startLine: number;
@@ -1 +1 @@
1
- {"version":3,"file":"assemble.d.ts","sourceRoot":"","sources":["../../src/contextpack/assemble.ts"],"names":[],"mappings":"AAQA,OAAO,EAEL,KAAK,aAAa,EAClB,KAAK,oBAAoB,EAIzB,KAAK,YAAY,EACjB,KAAK,iBAAiB,EACtB,KAAK,gBAAgB,EACrB,KAAK,mBAAmB,EACxB,KAAK,cAAc,EACnB,KAAK,aAAa,EAClB,KAAK,iBAAiB,EACvB,MAAM,iDAAiD,CAAC;AAIzD,OAAO,EAAgB,KAAK,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAChE,OAAO,EAAoB,KAAK,YAAY,EAAE,MAAM,eAAe,CAAC;AAIpE,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,KAAK,EAAE,aAAa,CAAC;IAC9B,QAAQ,CAAC,KAAK,EAAE,cAAc,CAAC;IAC/B,QAAQ,CAAC,MAAM,EAAE,iBAAiB,CAAC;IACnC,QAAQ,CAAC,KAAK,EAAE,SAAS,YAAY,EAAE,CAAC;IACxC,QAAQ,CAAC,MAAM,EAAE,SAAS,aAAa,EAAE,CAAC;IAC1C,QAAQ,CAAC,kBAAkB,EAAE,SAAS,mBAAmB,EAAE,CAAC;IAC5D,QAAQ,CAAC,QAAQ,EAAE,WAAW,CAAC,MAAM,EAAE,aAAa,CAAC,CAAC;IACtD,QAAQ,CAAC,aAAa,CAAC,EAAE,SAAS,MAAM,EAAE,GAAG,SAAS,CAAC;IACvD,QAAQ,CAAC,YAAY,CAAC,EAAE,gBAAgB,CAAC;IACzC,QAAQ,CAAC,kBAAkB,CAAC,EAAE,SAAS,iBAAiB,EAAE,CAAC;CAC5D;AAED,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;CAC1B;AAED,MAAM,MAAM,aAAa,GAAG,MAAM,GAAG,aAAa,GAAG,SAAS,aAAa,EAAE,CAAC;AAE9E,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,kBAAkB,CAAC,EAAE,MAAM,CAAC;IACrC,QAAQ,CAAC,aAAa,CAAC,EAAE,WAAW,CAAC,MAAM,CAAC,CAAC;IAC7C,QAAQ,CAAC,QAAQ,CAAC,EAAE,YAAY,CAAC;IACjC,QAAQ,CAAC,UAAU,CAAC,EAAE,UAAU,CAAC;IACjC,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,MAAM,CAAC;CAC/B;AAED,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,IAAI,EAAE,oBAAoB,CAAC;IACpC,QAAQ,CAAC,SAAS,EAAE,OAAO,CAAC;CAC7B;AA0fD,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,aAAa,EAAE,OAAO,CAAC,EAAE,eAAe,GAAG,MAAM,CAQ3F;AAED,wBAAsB,mBAAmB,CACvC,KAAK,EAAE,aAAa,EACpB,OAAO,CAAC,EAAE,eAAe,GACxB,OAAO,CAAC,cAAc,CAAC,CAoCzB"}
1
+ {"version":3,"file":"assemble.d.ts","sourceRoot":"","sources":["../../src/contextpack/assemble.ts"],"names":[],"mappings":"AAQA,OAAO,EAEL,KAAK,aAAa,EAClB,KAAK,oBAAoB,EACzB,KAAK,sBAAsB,EAI3B,KAAK,YAAY,EACjB,KAAK,iBAAiB,EACtB,KAAK,gBAAgB,EACrB,KAAK,mBAAmB,EACxB,KAAK,cAAc,EACnB,KAAK,aAAa,EAClB,KAAK,iBAAiB,EACvB,MAAM,iDAAiD,CAAC;AAIzD,OAAO,EAAgB,KAAK,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAChE,OAAO,EAAoB,KAAK,YAAY,EAAE,MAAM,eAAe,CAAC;AAIpE,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,KAAK,EAAE,aAAa,CAAC;IAC9B,QAAQ,CAAC,KAAK,EAAE,cAAc,CAAC;IAC/B,QAAQ,CAAC,MAAM,EAAE,iBAAiB,CAAC;IACnC,QAAQ,CAAC,KAAK,EAAE,SAAS,YAAY,EAAE,CAAC;IACxC,QAAQ,CAAC,MAAM,EAAE,SAAS,aAAa,EAAE,CAAC;IAC1C,QAAQ,CAAC,kBAAkB,EAAE,SAAS,mBAAmB,EAAE,CAAC;IAC5D,QAAQ,CAAC,QAAQ,EAAE,WAAW,CAAC,MAAM,EAAE,aAAa,CAAC,CAAC;IACtD,QAAQ,CAAC,aAAa,CAAC,EAAE,SAAS,MAAM,EAAE,GAAG,SAAS,CAAC;IACvD,QAAQ,CAAC,YAAY,CAAC,EAAE,gBAAgB,CAAC;IACzC,QAAQ,CAAC,kBAAkB,CAAC,EAAE,SAAS,iBAAiB,EAAE,CAAC;IAE3D,QAAQ,CAAC,WAAW,CAAC,EAAE,sBAAsB,GAAG,SAAS,CAAC;CAC3D;AAED,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;CAC1B;AAED,MAAM,MAAM,aAAa,GAAG,MAAM,GAAG,aAAa,GAAG,SAAS,aAAa,EAAE,CAAC;AAE9E,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,kBAAkB,CAAC,EAAE,MAAM,CAAC;IACrC,QAAQ,CAAC,aAAa,CAAC,EAAE,WAAW,CAAC,MAAM,CAAC,CAAC;IAC7C,QAAQ,CAAC,QAAQ,CAAC,EAAE,YAAY,CAAC;IACjC,QAAQ,CAAC,UAAU,CAAC,EAAE,UAAU,CAAC;IACjC,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,MAAM,CAAC;CAC/B;AAED,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,IAAI,EAAE,oBAAoB,CAAC;IACpC,QAAQ,CAAC,SAAS,EAAE,OAAO,CAAC;CAC7B;AA8gBD,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,aAAa,EAAE,OAAO,CAAC,EAAE,eAAe,GAAG,MAAM,CAQ3F;AAED,wBAAsB,mBAAmB,CACvC,KAAK,EAAE,aAAa,EACpB,OAAO,CAAC,EAAE,eAAe,GACxB,OAAO,CAAC,cAAc,CAAC,CAoCzB"}
@@ -273,6 +273,7 @@ function buildPack(input, plan, nowMs) {
273
273
  uncertainty: plan.uncertainty,
274
274
  emittedAtMs: nowMs,
275
275
  ledgerRef: undefined,
276
+ ...(input.diagnostics !== undefined ? { diagnostics: input.diagnostics } : {}),
276
277
  };
277
278
  }
278
279
  // ─── Public facade ────────────────────────────────────────────────────────────
@@ -354,6 +355,23 @@ function cacheOmitted(entry) {
354
355
  reason: entry.reason,
355
356
  };
356
357
  }
358
+ // Diagnostics are carried verbatim onto the pack, so two runs that differ ONLY in ranking
359
+ // explanation must not collide on a cached pack. Returns undefined when absent (serializes away,
360
+ // keeping legacy cache keys byte-identical).
361
+ function cacheDiagnostics(diagnostics) {
362
+ if (diagnostics === undefined) {
363
+ return undefined;
364
+ }
365
+ return {
366
+ rankedCandidates: diagnostics.rankedCandidates.map((entry) => ({
367
+ scopePath: entry.scopePath,
368
+ bucket: entry.bucket,
369
+ score: entry.score,
370
+ ecosystem: entry.ecosystem,
371
+ signals: entry.signals.map((signal) => ({ name: signal.name, value: signal.value })),
372
+ })),
373
+ };
374
+ }
357
375
  function cacheExcerptWindow(window) {
358
376
  return {
359
377
  startLine: window.startLine,
@@ -387,6 +405,7 @@ function buildCacheAtomIds(input, resolved) {
387
405
  : undefined,
388
406
  ranked: input.ranked.map(cacheCandidate),
389
407
  omittedFromRanking: input.omittedFromRanking.map(cacheOmitted),
408
+ diagnostics: cacheDiagnostics(input.diagnostics),
390
409
  excerpts: cacheExcerptIdentity(input),
391
410
  maxBytesPerExcerpt: resolved.maxBytesPerExcerpt,
392
411
  editablePaths: [...resolved.editablePaths].sort(),
package/dist/index.d.ts CHANGED
@@ -6,4 +6,6 @@ export * from "./ranking/index.js";
6
6
  export * from "./contextpack/index.js";
7
7
  export * from "./qualityIntelligence/index.js";
8
8
  export * from "./promptEnhancer/index.js";
9
+ export * from "./context-budget/index.js";
10
+ export * from "./observations/index.js";
9
11
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAUA,YAAY,EAAE,kBAAkB,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AAE7E,cAAc,uBAAuB,CAAC;AACtC,cAAc,8BAA8B,CAAC;AAG7C,cAAc,oBAAoB,CAAC;AAGnC,cAAc,oBAAoB,CAAC;AAGnC,cAAc,wBAAwB,CAAC;AAIvC,cAAc,gCAAgC,CAAC;AAG/C,cAAc,2BAA2B,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAUA,YAAY,EAAE,kBAAkB,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AAE7E,cAAc,uBAAuB,CAAC;AACtC,cAAc,8BAA8B,CAAC;AAG7C,cAAc,oBAAoB,CAAC;AAGnC,cAAc,oBAAoB,CAAC;AAGnC,cAAc,wBAAwB,CAAC;AAIvC,cAAc,gCAAgC,CAAC;AAG/C,cAAc,2BAA2B,CAAC;AAG1C,cAAc,2BAA2B,CAAC;AAG1C,cAAc,yBAAyB,CAAC"}
package/dist/index.js CHANGED
@@ -11,3 +11,7 @@ export * from "./contextpack/index.js";
11
11
  export * from "./qualityIntelligence/index.js";
12
12
  // ─── Prompt Enhancer workflow execution (Epic #1307, Issue #1314) ─────────────
13
13
  export * from "./promptEnhancer/index.js";
14
+ // ─── Deterministic context-budget allocator (ADR-0052, context-engineering milestone) ──
15
+ export * from "./context-budget/index.js";
16
+ // ─── Tool-observation shapers (ADR-0054, PR3-W3, context-engineering milestone) ──
17
+ export * from "./observations/index.js";
@@ -0,0 +1,6 @@
1
+ import { type CommandResult, type ShapedCommandObservation } from "@oscharko-dev/keiko-contracts";
2
+ export interface ShapeCommandOptions {
3
+ readonly observationId?: string | undefined;
4
+ }
5
+ export declare function shapeCommandObservation(result: CommandResult, opts?: ShapeCommandOptions): ShapedCommandObservation;
6
+ //# sourceMappingURL=command.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"command.d.ts","sourceRoot":"","sources":["../../src/observations/command.ts"],"names":[],"mappings":"AAOA,OAAO,EAEL,KAAK,aAAa,EAClB,KAAK,wBAAwB,EAE9B,MAAM,+BAA+B,CAAC;AAWvC,MAAM,WAAW,mBAAmB;IAClC,QAAQ,CAAC,aAAa,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CAC7C;AA0CD,wBAAgB,uBAAuB,CACrC,MAAM,EAAE,aAAa,EACrB,IAAI,CAAC,EAAE,mBAAmB,GACzB,wBAAwB,CA6B1B"}
@@ -0,0 +1,67 @@
1
+ // Pure shaper: CommandResult -> ShapedCommandObservation (ADR-0054, PR3-W3, D4). No IO, no clock,
2
+ // no randomness. Total — never throws on empty streams. The exit-code/duration/timedOut/truncated
3
+ // signals are preserved verbatim; each non-empty stream contributes a redacted, byte-bounded
4
+ // excerpt whose combined bytes stay within MAX_OBSERVATION_EXCERPT_BYTES. Injection signals are
5
+ // recorded content-free over the already-redacted excerpt text. A rehydration handle is attached
6
+ // ONLY when the output was truncated (there is omitted content worth re-fetching in PR5).
7
+ import { MAX_OBSERVATION_EXCERPT_BYTES, } from "@oscharko-dev/keiko-contracts";
8
+ import { boundExcerpt, buildToolRehydrationHandle, estimateTokens, injectionSignalsFor, makeObservationId, utf8ByteLength, } from "./shared.js";
9
+ const TRUNCATED_NOT_PERSISTED = "tool output not persisted in PR3 (artifact store wired in PR5)";
10
+ // Builds the bounded excerpts, allocating the shared MAX_OBSERVATION_EXCERPT_BYTES budget across the
11
+ // non-empty streams in order (stdout first, then stderr from the remaining budget) so the SUM of
12
+ // excerpt bytes never exceeds the cap. Each excerpt is redacted before clamping (boundExcerpt).
13
+ function buildExcerpts(sources) {
14
+ const excerpts = [];
15
+ let remaining = MAX_OBSERVATION_EXCERPT_BYTES;
16
+ for (const source of sources) {
17
+ if (source.text.length === 0 || remaining <= 0) {
18
+ continue;
19
+ }
20
+ const text = boundExcerpt(source.text, remaining);
21
+ if (text.length === 0) {
22
+ continue;
23
+ }
24
+ const bytes = utf8ByteLength(text);
25
+ excerpts.push({ stream: source.stream, bytes, text });
26
+ remaining -= bytes;
27
+ }
28
+ return excerpts;
29
+ }
30
+ function injectionFor(excerpts) {
31
+ const combined = excerpts.map((excerpt) => excerpt.text).join("\n");
32
+ const summary = injectionSignalsFor(combined);
33
+ return {
34
+ injectionSignalCount: summary.count,
35
+ hasCriticalInjectionSignal: summary.critical,
36
+ };
37
+ }
38
+ export function shapeCommandObservation(result, opts) {
39
+ const observationId = opts?.observationId ?? makeObservationId("");
40
+ const excerpts = buildExcerpts([
41
+ { stream: "stdout", text: result.stdout },
42
+ { stream: "stderr", text: result.stderr },
43
+ ]);
44
+ const injection = injectionFor(excerpts);
45
+ return {
46
+ kind: "command",
47
+ observationId,
48
+ exitCode: result.exitCode,
49
+ durationMs: result.durationMs,
50
+ timedOut: result.timedOut,
51
+ truncated: result.truncated,
52
+ ...(result.omittedByteCount !== undefined ? { omittedByteCount: result.omittedByteCount } : {}),
53
+ excerpts,
54
+ injectionSignalCount: injection.injectionSignalCount,
55
+ hasCriticalInjectionSignal: injection.hasCriticalInjectionSignal,
56
+ ...(result.truncated
57
+ ? {
58
+ rehydration: buildToolRehydrationHandle({
59
+ artifactSeed: `${observationId}:full`,
60
+ itemCount: 1,
61
+ approxTokens: estimateTokens(excerpts.map((excerpt) => excerpt.text).join("\n")),
62
+ notPersistedReason: TRUNCATED_NOT_PERSISTED,
63
+ }),
64
+ }
65
+ : {}),
66
+ };
67
+ }
@@ -0,0 +1,5 @@
1
+ export { shapeCommandObservation, type ShapeCommandOptions } from "./command.js";
2
+ export { shapeTestObservation, type ShapeTestOptions } from "./test.js";
3
+ export { shapeSearchObservation, type ShapeSearchOptions } from "./search.js";
4
+ export { makeObservationId, injectionSignalsFor, boundExcerpt, buildToolRehydrationHandle, type InjectionSummary, type RehydrationHandleInput, } from "./shared.js";
5
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/observations/index.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,uBAAuB,EAAE,KAAK,mBAAmB,EAAE,MAAM,cAAc,CAAC;AACjF,OAAO,EAAE,oBAAoB,EAAE,KAAK,gBAAgB,EAAE,MAAM,WAAW,CAAC;AACxE,OAAO,EAAE,sBAAsB,EAAE,KAAK,kBAAkB,EAAE,MAAM,aAAa,CAAC;AAC9E,OAAO,EACL,iBAAiB,EACjB,mBAAmB,EACnB,YAAY,EACZ,0BAA0B,EAC1B,KAAK,gBAAgB,EACrB,KAAK,sBAAsB,GAC5B,MAAM,aAAa,CAAC"}
@@ -0,0 +1,6 @@
1
+ // Barrel for the tool-observation shapers (ADR-0054, PR3-W3). Re-exports the three pure shapers and
2
+ // the shared helpers worth exposing to the PR4 lane assembler. No live browser shaper in PR3 (D8).
3
+ export { shapeCommandObservation } from "./command.js";
4
+ export { shapeTestObservation } from "./test.js";
5
+ export { shapeSearchObservation } from "./search.js";
6
+ export { makeObservationId, injectionSignalsFor, boundExcerpt, buildToolRehydrationHandle, } from "./shared.js";
@@ -0,0 +1,9 @@
1
+ import { type ShapedSearchObservation } from "@oscharko-dev/keiko-contracts";
2
+ import type { SearchResult } from "@oscharko-dev/keiko-workspace";
3
+ export interface ShapeSearchOptions {
4
+ readonly observationId?: string | undefined;
5
+ readonly query?: string | undefined;
6
+ readonly searchKind?: string | undefined;
7
+ }
8
+ export declare function shapeSearchObservation(result: SearchResult, opts?: ShapeSearchOptions): ShapedSearchObservation;
9
+ //# sourceMappingURL=search.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"search.d.ts","sourceRoot":"","sources":["../../src/observations/search.ts"],"names":[],"mappings":"AAWA,OAAO,EAGL,KAAK,uBAAuB,EAE7B,MAAM,+BAA+B,CAAC;AAEvC,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,+BAA+B,CAAC;AAIlE,MAAM,WAAW,kBAAkB;IACjC,QAAQ,CAAC,aAAa,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC5C,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACpC,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CAC1C;AAiBD,wBAAgB,sBAAsB,CACpC,MAAM,EAAE,YAAY,EACpB,IAAI,CAAC,EAAE,kBAAkB,GACxB,uBAAuB,CAkBzB"}
@@ -0,0 +1,43 @@
1
+ // Pure shaper: SearchResult -> ShapedSearchObservation (ADR-0054, PR3-W3, D4). No IO, no clock, no
2
+ // randomness. Total — never throws on empty atoms. Preserves the top-scoring file ranges so the
3
+ // PR4 lane assembler can cite relevant matches without including any raw atom text. scopePath is
4
+ // allowed here: this is the internal tool-observations lane, not the path-free browser summary.
5
+ //
6
+ // SOURCE NOTE: SearchResult (keiko-workspace/repoSearch.ts) carries the atoms + truncation flag but
7
+ // NOT the original query string or the search kind (those are inputs to searchText/findFiles, not
8
+ // outputs). The caller supplies them via opts so the shaper stays a pure projection. The query is
9
+ // the untrusted input (user-typed or model-generated): it is redacted and byte-bounded, and the
10
+ // injection summary is computed over the redacted query, content-free.
11
+ import { MAX_OBSERVATION_QUERY_BYTES, MAX_TOP_RANGES, } from "@oscharko-dev/keiko-contracts";
12
+ import { boundExcerpt, injectionSignalsFor, makeObservationId } from "./shared.js";
13
+ const DEFAULT_SEARCH_KIND = "text";
14
+ function toRange(atom) {
15
+ const startLine = atom.lineRange?.startLine ?? 0;
16
+ const endLine = atom.lineRange?.endLine ?? 0;
17
+ return { scopePath: atom.scopePath, startLine, endLine, score: atom.score };
18
+ }
19
+ // Top MAX_TOP_RANGES atoms by descending score. Sorts a shallow copy (the source array is readonly
20
+ // and must not be mutated). Ties keep their relative input order via a stable comparator.
21
+ function topRanges(atoms) {
22
+ const sorted = [...atoms].sort((a, b) => b.score - a.score);
23
+ return sorted.slice(0, MAX_TOP_RANGES).map(toRange);
24
+ }
25
+ export function shapeSearchObservation(result, opts) {
26
+ const observationId = opts?.observationId ?? makeObservationId("");
27
+ const query = boundExcerpt(opts?.query ?? "", MAX_OBSERVATION_QUERY_BYTES);
28
+ const ranges = topRanges(result.atoms);
29
+ const candidateCount = result.atoms.length;
30
+ const injection = injectionSignalsFor(query);
31
+ return {
32
+ kind: "search",
33
+ observationId,
34
+ query,
35
+ searchKind: opts?.searchKind ?? DEFAULT_SEARCH_KIND,
36
+ candidateCount,
37
+ topRanges: ranges,
38
+ omittedCount: candidateCount - ranges.length,
39
+ truncated: result.truncated,
40
+ injectionSignalCount: injection.count,
41
+ hasCriticalInjectionSignal: injection.critical,
42
+ };
43
+ }
@@ -0,0 +1,18 @@
1
+ import { estimateTokens, type ContextToolRehydrationHandle } from "@oscharko-dev/keiko-contracts";
2
+ export interface InjectionSummary {
3
+ readonly count: number;
4
+ readonly critical: boolean;
5
+ }
6
+ export declare function makeObservationId(seed: string): string;
7
+ export declare function injectionSignalsFor(text: string): InjectionSummary;
8
+ export declare function boundExcerpt(text: string, maxBytes: number): string;
9
+ export declare function utf8ByteLength(text: string): number;
10
+ export interface RehydrationHandleInput {
11
+ readonly artifactSeed: string;
12
+ readonly itemCount: number;
13
+ readonly approxTokens: number;
14
+ readonly notPersistedReason?: string | undefined;
15
+ }
16
+ export declare function buildToolRehydrationHandle(input: RehydrationHandleInput): ContextToolRehydrationHandle;
17
+ export { estimateTokens };
18
+ //# sourceMappingURL=shared.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"shared.d.ts","sourceRoot":"","sources":["../../src/observations/shared.ts"],"names":[],"mappings":"AAOA,OAAO,EAEL,cAAc,EAEd,KAAK,4BAA4B,EAClC,MAAM,+BAA+B,CAAC;AAavC,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAC;CAC5B;AAID,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAEtD;AAKD,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,GAAG,gBAAgB,CAOlE;AAKD,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CAWnE;AAGD,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAEnD;AAED,MAAM,WAAW,sBAAsB;IACrC,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,kBAAkB,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CAClD;AAKD,wBAAgB,0BAA0B,CACxC,KAAK,EAAE,sBAAsB,GAC5B,4BAA4B,CAY9B;AAED,OAAO,EAAE,cAAc,EAAE,CAAC"}
@@ -0,0 +1,63 @@
1
+ // Shared, pure helpers for the tool-observation shapers (ADR-0054, PR3-W3). No IO, no clock, no
2
+ // randomness. Every untrusted free-text string is scrubbed via redact() from keiko-security BEFORE
3
+ // it is clamped or measured (the defense-in-depth boundary established by the PR2 compaction
4
+ // helpers). Injection detection is CONTENT-FREE by construction: detectPromptInjectionSignals
5
+ // returns only {code, severity, matchCount}; we store an aggregate count and a boolean and NEVER
6
+ // the matched text. No new package edge: contracts/security/workspace are already dependencies.
7
+ import { CONTEXT_ENGINEERING_SCHEMA_VERSION, estimateTokens, } from "@oscharko-dev/keiko-contracts";
8
+ import { hashExcerptContent } from "@oscharko-dev/keiko-workspace";
9
+ import { detectPromptInjectionSignals, hasCriticalInjectionSignal, redact, } from "@oscharko-dev/keiko-security";
10
+ // The lane every shaped tool observation belongs to (ADR-0052 taxonomy).
11
+ const TOOL_OBSERVATIONS_LANE = "tool-observations";
12
+ // Stable, reproducible observation id: SHA-256 hex of the seed (typically the toolCallId). Total —
13
+ // hashExcerptContent never throws; an empty seed yields the well-defined hash of zero bytes.
14
+ export function makeObservationId(seed) {
15
+ return hashExcerptContent(seed);
16
+ }
17
+ // CONTENT-FREE injection signal summary over untrusted text. Sums each signal's matchCount for the
18
+ // aggregate count and derives the critical flag from the authoritative severity helper. The matched
19
+ // text is never inspected by the caller — only the returned counts/boolean are persisted.
20
+ export function injectionSignalsFor(text) {
21
+ const signals = detectPromptInjectionSignals(text);
22
+ let count = 0;
23
+ for (const signal of signals) {
24
+ count += signal.matchCount;
25
+ }
26
+ return { count, critical: hasCriticalInjectionSignal(signals) };
27
+ }
28
+ // Redact-then-clamp: redact() runs FIRST so a secret can never survive into the bounded excerpt,
29
+ // then the redacted text is clamped to maxBytes of UTF-8 without splitting a multibyte character
30
+ // (the repoSearch clampToBytes pattern: encode, subarray, lossy-decode, trim the replacement char).
31
+ export function boundExcerpt(text, maxBytes) {
32
+ const redacted = redact(text);
33
+ if (maxBytes <= 0) {
34
+ return "";
35
+ }
36
+ const encoded = new TextEncoder().encode(redacted);
37
+ if (encoded.length <= maxBytes) {
38
+ return redacted;
39
+ }
40
+ const buffer = encoded.subarray(0, maxBytes);
41
+ return new TextDecoder("utf-8", { fatal: false }).decode(buffer).replace(/�+$/u, "");
42
+ }
43
+ // UTF-8 byte length of a string (the bytes field on a ShapedStreamExcerpt).
44
+ export function utf8ByteLength(text) {
45
+ return new TextEncoder().encode(text).length;
46
+ }
47
+ // Builds the content-free ContextToolRehydrationHandle. artifactId = hashExcerptContent(artifactSeed)
48
+ // — deterministic and stable. notPersistedReason is included only when supplied (exactOptional:
49
+ // conditional spread, never assigned undefined). approxTokens is passed through unchanged.
50
+ export function buildToolRehydrationHandle(input) {
51
+ return {
52
+ schemaVersion: CONTEXT_ENGINEERING_SCHEMA_VERSION,
53
+ laneId: TOOL_OBSERVATIONS_LANE,
54
+ kind: "tool-result",
55
+ artifactId: makeObservationId(input.artifactSeed),
56
+ itemCount: input.itemCount,
57
+ approxTokens: input.approxTokens,
58
+ ...(input.notPersistedReason !== undefined
59
+ ? { notPersistedReason: input.notPersistedReason }
60
+ : {}),
61
+ };
62
+ }
63
+ export { estimateTokens };
@@ -0,0 +1,6 @@
1
+ import { type ShapedTestObservation, type VerificationResult } from "@oscharko-dev/keiko-contracts";
2
+ export interface ShapeTestOptions {
3
+ readonly observationId?: string | undefined;
4
+ }
5
+ export declare function shapeTestObservation(result: VerificationResult, opts?: ShapeTestOptions): ShapedTestObservation;
6
+ //# sourceMappingURL=test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"test.d.ts","sourceRoot":"","sources":["../../src/observations/test.ts"],"names":[],"mappings":"AAYA,OAAO,EAEL,KAAK,qBAAqB,EAC1B,KAAK,kBAAkB,EACxB,MAAM,+BAA+B,CAAC;AAUvC,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,aAAa,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CAC7C;AAQD,wBAAgB,oBAAoB,CAClC,MAAM,EAAE,kBAAkB,EAC1B,IAAI,CAAC,EAAE,gBAAgB,GACtB,qBAAqB,CA6BvB"}
@@ -0,0 +1,47 @@
1
+ // Pure shaper: VerificationResult -> ShapedTestObservation (ADR-0054, PR3-W3, D4). No IO, no clock,
2
+ // no randomness. Total — never throws.
3
+ //
4
+ // HONEST SOURCE NOTE: the live VerificationResult (keiko-contracts/verification.ts) carries NO
5
+ // per-test structured data — no pass/fail/skip counts, no failing test names, no stack frames. Its
6
+ // outputSummary is a redacted DIGEST string (e.g. "command output captured (N bytes) and omitted
7
+ // from summary" — see keiko-verification/src/orchestrator.ts outputDigest), not a parseable test
8
+ // log, and the per-status counts on VerificationReport count STEPS, not individual tests. Per the
9
+ // PR3 constraint we do NOT invent counts or names: counts default to zeros and the name/frame arrays
10
+ // stay empty until a producer supplies genuinely structured data. The reliably-present fields we DO
11
+ // project: kind, status, exitCode, durationMs, truncated, and the redacted outputSummary.
12
+ import {} from "@oscharko-dev/keiko-contracts";
13
+ import { boundExcerpt, buildToolRehydrationHandle, estimateTokens, injectionSignalsFor, makeObservationId, } from "./shared.js";
14
+ const TRUNCATED_NOT_PERSISTED = "tool output not persisted in PR3 (artifact store wired in PR5)";
15
+ // VerificationResult has no per-test breakdown; the only honest count is all-zero. A future producer
16
+ // with structured test data populates this via a richer overload, not by inventing numbers here.
17
+ const EMPTY_COUNTS = { passed: 0, failed: 0, skipped: 0 };
18
+ export function shapeTestObservation(result, opts) {
19
+ const observationId = opts?.observationId ?? makeObservationId("");
20
+ const outputSummary = boundExcerpt(result.outputSummary, Number.MAX_SAFE_INTEGER);
21
+ const injection = injectionSignalsFor(outputSummary);
22
+ return {
23
+ kind: "test",
24
+ observationId,
25
+ verificationKind: result.kind,
26
+ status: result.status,
27
+ exitCode: result.exitCode,
28
+ durationMs: result.durationMs,
29
+ truncated: result.truncated,
30
+ counts: EMPTY_COUNTS,
31
+ failingTestNames: [],
32
+ stackFrameExcerpts: [],
33
+ outputSummary,
34
+ injectionSignalCount: injection.count,
35
+ hasCriticalInjectionSignal: injection.critical,
36
+ ...(result.truncated
37
+ ? {
38
+ rehydration: buildToolRehydrationHandle({
39
+ artifactSeed: `${observationId}:full`,
40
+ itemCount: 1,
41
+ approxTokens: estimateTokens(outputSummary),
42
+ notPersistedReason: TRUNCATED_NOT_PERSISTED,
43
+ }),
44
+ }
45
+ : {}),
46
+ };
47
+ }
@@ -1 +1 @@
1
- {"version":3,"file":"anchors.d.ts","sourceRoot":"","sources":["../../src/planner/anchors.ts"],"names":[],"mappings":"AA+LA,MAAM,MAAM,gBAAgB,GAAG,SAAS,GAAG,YAAY,GAAG,MAAM,GAAG,QAAQ,CAAC;AAE5E,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,IAAI,EAAE,gBAAgB,CAAC;CACjC;AAED,MAAM,WAAW,qBAAqB;IACpC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;CAC7B;AAED,MAAM,WAAW,sBAAsB;IACrC,QAAQ,CAAC,OAAO,EAAE,SAAS,YAAY,EAAE,CAAC;IAC1C,QAAQ,CAAC,SAAS,EAAE,OAAO,CAAC;IAC5B,QAAQ,CAAC,gBAAgB,EAAE,MAAM,CAAC;CACnC;AAgHD,wBAAgB,cAAc,CAAC,KAAK,EAAE,qBAAqB,GAAG,sBAAsB,CAoBnF"}
1
+ {"version":3,"file":"anchors.d.ts","sourceRoot":"","sources":["../../src/planner/anchors.ts"],"names":[],"mappings":"AAgMA,MAAM,MAAM,gBAAgB,GAAG,SAAS,GAAG,YAAY,GAAG,MAAM,GAAG,QAAQ,CAAC;AAE5E,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,IAAI,EAAE,gBAAgB,CAAC;CACjC;AAED,MAAM,WAAW,qBAAqB;IACpC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;CAC7B;AAED,MAAM,WAAW,sBAAsB;IACrC,QAAQ,CAAC,OAAO,EAAE,SAAS,YAAY,EAAE,CAAC;IAC1C,QAAQ,CAAC,SAAS,EAAE,OAAO,CAAC;IAC5B,QAAQ,CAAC,gBAAgB,EAAE,MAAM,CAAC;CACnC;AAgHD,wBAAgB,cAAc,CAAC,KAAK,EAAE,qBAAqB,GAAG,sBAAsB,CAqBnF"}
@@ -158,6 +158,7 @@ const QUOTED_DOUBLE_RE = /"([^"\n]+)"/g;
158
158
  const QUOTED_SINGLE_RE = /'([^'\n]+)'/g;
159
159
  const BACKTICK_RE = /`([^`\n]+)`/g;
160
160
  const PATH_RE = /(?:[\w.-]+\/)+[\w.-]+\.[A-Za-z]{1,8}/g;
161
+ const API_ROUTE_RE = /(^|[^A-Za-z0-9_.-])((?:\/[A-Za-z0-9_.:{}-]+){2,})/g;
161
162
  // Requires a genuine lower/digit -> upper transition so all-caps acronyms and SHOUTING words
162
163
  // (WHY, HTTP, BROKEN) are NOT mistaken for code identifiers. A spurious 0.85 identifier anchor
163
164
  // would both satisfy the clarification gate for a vague question and seed symbol-file retrieval
@@ -195,7 +196,7 @@ function collectMatches(source, pattern, kind, weight, out) {
195
196
  let match = re.exec(source);
196
197
  while (match !== null) {
197
198
  const full = match[0];
198
- const captured = match[1] ?? full;
199
+ const captured = match[2] ?? match[1] ?? full;
199
200
  pushAnchor(out, captured, kind, weight);
200
201
  parts.push(source.slice(cursor, match.index));
201
202
  parts.push(" ".repeat(full.length));
@@ -280,6 +281,7 @@ export function extractAnchors(input) {
280
281
  let remaining = collectMatches(text, QUOTED_DOUBLE_RE, "quoted", 1, collected);
281
282
  remaining = collectMatches(remaining, QUOTED_SINGLE_RE, "quoted", 1, collected);
282
283
  remaining = collectMatches(remaining, BACKTICK_RE, "identifier", 0.9, collected);
284
+ remaining = collectMatches(remaining, API_ROUTE_RE, "path", 0.95, collected);
283
285
  remaining = collectMatches(remaining, PATH_RE, "path", 0.95, collected);
284
286
  remaining = collectMatches(remaining, CAMEL_IDENTIFIER_RE, "identifier", 0.85, collected);
285
287
  remaining = collectTechnicalTerms(remaining, collected);
@@ -1 +1 @@
1
- {"version":3,"file":"intent.d.ts","sourceRoot":"","sources":["../../src/planner/intent.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,iDAAiD,CAAC;AAErF,MAAM,MAAM,eAAe,GACvB,kBAAkB,GAClB,qBAAqB,GACrB,sBAAsB,GACtB,mBAAmB,GACnB,sBAAsB,CAAC;AAE3B,MAAM,WAAW,6BAA6B;IAC5C,QAAQ,CAAC,MAAM,EAAE,eAAe,CAAC;IACjC,QAAQ,CAAC,eAAe,EAAE,SAAS,MAAM,EAAE,CAAC;CAC7C;AAuJD,wBAAgB,uBAAuB,CACrC,SAAS,EAAE,MAAM,EACjB,MAAM,CAAC,EAAE,aAAa,GACrB,6BAA6B,CAqB/B"}
1
+ {"version":3,"file":"intent.d.ts","sourceRoot":"","sources":["../../src/planner/intent.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,iDAAiD,CAAC;AAGrF,MAAM,MAAM,eAAe,GACvB,kBAAkB,GAClB,qBAAqB,GACrB,sBAAsB,GACtB,mBAAmB,GACnB,sBAAsB,CAAC;AAE3B,MAAM,WAAW,6BAA6B;IAC5C,QAAQ,CAAC,MAAM,EAAE,eAAe,CAAC;IACjC,QAAQ,CAAC,eAAe,EAAE,SAAS,MAAM,EAAE,CAAC;CAC7C;AA4JD,wBAAgB,uBAAuB,CACrC,SAAS,EAAE,MAAM,EACjB,MAAM,CAAC,EAAE,aAAa,GACrB,6BAA6B,CAqB/B"}
@@ -1,5 +1,6 @@
1
1
  // Deterministic retrieval-intent classification for connected-context planning.
2
2
  // This module is intentionally pure: no IO, no clock, no model calls.
3
+ import { ecosystemMetadataIntentPatterns } from "@oscharko-dev/keiko-workspace";
3
4
  const BASIC_STOP_WORDS = new Set([
4
5
  "the",
5
6
  "and",
@@ -77,6 +78,11 @@ const PROJECT_METADATA_PATTERNS = [
77
78
  { term: "nextjs", pattern: /\bnext(?:\.js)?\b/iu },
78
79
  { term: "react", pattern: /\breact\b/iu },
79
80
  { term: "eslint", pattern: /\beslint\b/iu },
81
+ // Polyglot ecosystem routing is sourced from the shared registry so questions like "Which Java
82
+ // version does this project use?" classify as project-metadata instead of generic code search.
83
+ // The established JS/TS terms above stay in place for compatibility; registry duplicates are
84
+ // harmless because matched terms are de-duplicated before classification.
85
+ ...ecosystemMetadataIntentPatterns,
80
86
  ];
81
87
  const REPOSITORY_OVERVIEW_PATTERNS = [
82
88
  { term: "architecture", pattern: /\barchitecture\b|\barchitektur\b/iu },
@@ -1 +1 @@
1
- {"version":3,"file":"rank.d.ts","sourceRoot":"","sources":["../../src/ranking/rank.ts"],"names":[],"mappings":"AAKA,OAAO,EAIL,KAAK,uBAAuB,EAG7B,MAAM,iDAAiD,CAAC;AAEzD,OAAO,EAIL,KAAK,aAAa,EAClB,KAAK,YAAY,EAClB,MAAM,aAAa,CAAC;AACrB,OAAO,EAAyC,KAAK,cAAc,EAAE,MAAM,cAAc,CAAC;AAC1F,OAAO,EAIL,KAAK,YAAY,EAClB,MAAM,cAAc,CAAC;AAEtB,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,OAAO,CAAC,EAAE,cAAc,CAAC;IAClC,QAAQ,CAAC,MAAM,CAAC,EAAE,IAAI,CAAC,aAAa,EAAE,OAAO,CAAC,CAAC;IAC/C,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,MAAM,CAAC;CAC/B;AAED,MAAM,WAAW,kBAAkB;IACjC,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,gBAAgB,EAAE,MAAM,CAAC;IAClC,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,aAAa,EAAE,QAAQ,CAAC,MAAM,CAAC,uBAAuB,EAAE,MAAM,CAAC,CAAC,CAAC;IAC1E,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;CAC5B;AAED,MAAM,WAAW,aAAc,SAAQ,YAAY;IACjD,QAAQ,CAAC,WAAW,EAAE,kBAAkB,CAAC;CAC1C;AA+JD,wBAAgB,cAAc,CAAC,KAAK,EAAE,YAAY,EAAE,OAAO,GAAE,cAAmB,GAAG,aAAa,CAyB/F"}
1
+ {"version":3,"file":"rank.d.ts","sourceRoot":"","sources":["../../src/ranking/rank.ts"],"names":[],"mappings":"AAKA,OAAO,EAIL,KAAK,uBAAuB,EAG7B,MAAM,iDAAiD,CAAC;AAEzD,OAAO,EAIL,KAAK,aAAa,EAClB,KAAK,YAAY,EAClB,MAAM,aAAa,CAAC;AACrB,OAAO,EAAkC,KAAK,cAAc,EAAE,MAAM,cAAc,CAAC;AACnF,OAAO,EAIL,KAAK,YAAY,EAClB,MAAM,cAAc,CAAC;AAEtB,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,OAAO,CAAC,EAAE,cAAc,CAAC;IAClC,QAAQ,CAAC,MAAM,CAAC,EAAE,IAAI,CAAC,aAAa,EAAE,OAAO,CAAC,CAAC;IAC/C,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,MAAM,CAAC;CAC/B;AAED,MAAM,WAAW,kBAAkB;IACjC,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,gBAAgB,EAAE,MAAM,CAAC;IAClC,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,aAAa,EAAE,QAAQ,CAAC,MAAM,CAAC,uBAAuB,EAAE,MAAM,CAAC,CAAC,CAAC;IAC1E,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;CAC5B;AAED,MAAM,WAAW,aAAc,SAAQ,YAAY;IACjD,QAAQ,CAAC,WAAW,EAAE,kBAAkB,CAAC;CAC1C;AA+JD,wBAAgB,cAAc,CAAC,KAAK,EAAE,YAAY,EAAE,OAAO,GAAE,cAAmB,GAAG,aAAa,CA2B/F"}
@@ -4,7 +4,7 @@
4
4
  // the returned diagnostics so UI/audit consumers can render zeros without conditionals.
5
5
  import { CANDIDATE_OMISSION_REASONS, isValidScopePath, } from "@oscharko-dev/keiko-contracts/connected-context";
6
6
  import { DEFAULT_FILTER_OPTIONS, filterCandidates, } from "./filter.js";
7
- import { DEFAULT_SCORING_WEIGHTS, computeScore } from "./scoring.js";
7
+ import { computeScore, weightsForIntent } from "./scoring.js";
8
8
  import { DEFAULT_GENERATED_PATTERNS, extractSignals, } from "./signals.js";
9
9
  const AUTO_DUPLICATE_CLUSTER_MIN = 3;
10
10
  const AUTO_DUPLICATE_BASENAME_EXEMPTIONS = new Set([
@@ -101,7 +101,7 @@ function deriveDuplicateHints(group, explicit) {
101
101
  function buildAnnotated(group, input, hints, weights) {
102
102
  const annotated = [];
103
103
  for (const [scopePath, atomsForPath] of group) {
104
- const signals = extractSignals(atomsForPath, input.anchors, hints);
104
+ const signals = extractSignals(atomsForPath, input.anchors, hints, input.context);
105
105
  const score = computeScore(signals, weights);
106
106
  const candidate = {
107
107
  scopePath,
@@ -139,7 +139,9 @@ export function rankCandidates(input, options = {}) {
139
139
  const startMs = clock();
140
140
  const frozenStartMs = () => startMs;
141
141
  const hints = resolveHints(input.hints);
142
- const weights = options.weights ?? DEFAULT_SCORING_WEIGHTS;
142
+ // Explicit weights still win (existing callers/tests unaffected); otherwise the intent picks the
143
+ // weights — DEFAULT for non-boosted intents and the no-intent path, so behavior is unchanged there.
144
+ const weights = options.weights ?? weightsForIntent(input.context?.retrievalIntent);
143
145
  const { valid, invalidPaths } = groupAtomsByPath(input.atoms);
144
146
  const rankingHints = { ...hints, duplicateOf: deriveDuplicateHints(valid, hints.duplicateOf) };
145
147
  const annotated = buildAnnotated(valid, input, rankingHints, weights);
@@ -7,7 +7,11 @@ export interface ScoringWeights {
7
7
  readonly testPairBonus: number;
8
8
  readonly stacktracePositionBonus: number;
9
9
  readonly generatedPenalty: number;
10
+ readonly canonicalMetadata?: number;
11
+ readonly structuralEdge?: number;
10
12
  }
11
13
  export declare const DEFAULT_SCORING_WEIGHTS: ScoringWeights;
14
+ export declare function isIntentBoosted(intent: string | undefined): boolean;
15
+ export declare function weightsForIntent(intent: string | undefined): ScoringWeights;
12
16
  export declare function computeScore(signals: ExtractedSignals, weights?: ScoringWeights): number;
13
17
  //# sourceMappingURL=scoring.d.ts.map