@oscharko-dev/keiko-workspace 0.2.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 (83) hide show
  1. package/dist/.tsbuildinfo +1 -0
  2. package/dist/binaryDetect.d.ts +6 -0
  3. package/dist/binaryDetect.d.ts.map +1 -0
  4. package/dist/binaryDetect.js +20 -0
  5. package/dist/contextPack.d.ts +24 -0
  6. package/dist/contextPack.d.ts.map +1 -0
  7. package/dist/contextPack.js +118 -0
  8. package/dist/detect.d.ts +5 -0
  9. package/dist/detect.d.ts.map +1 -0
  10. package/dist/detect.js +144 -0
  11. package/dist/discovery.d.ts +10 -0
  12. package/dist/discovery.d.ts.map +1 -0
  13. package/dist/discovery.js +199 -0
  14. package/dist/document-extraction.d.ts +44 -0
  15. package/dist/document-extraction.d.ts.map +1 -0
  16. package/dist/document-extraction.js +372 -0
  17. package/dist/errors.d.ts +3 -0
  18. package/dist/errors.d.ts.map +1 -0
  19. package/dist/errors.js +4 -0
  20. package/dist/fs.d.ts +25 -0
  21. package/dist/fs.d.ts.map +1 -0
  22. package/dist/fs.js +69 -0
  23. package/dist/gitHistory.d.ts +3 -0
  24. package/dist/gitHistory.d.ts.map +1 -0
  25. package/dist/gitHistory.js +317 -0
  26. package/dist/ignore.d.ts +15 -0
  27. package/dist/ignore.d.ts.map +1 -0
  28. package/dist/ignore.js +248 -0
  29. package/dist/importGraph.d.ts +3 -0
  30. package/dist/importGraph.d.ts.map +1 -0
  31. package/dist/importGraph.js +131 -0
  32. package/dist/index.d.ts +27 -0
  33. package/dist/index.d.ts.map +1 -0
  34. package/dist/index.js +25 -0
  35. package/dist/paths.d.ts +3 -0
  36. package/dist/paths.d.ts.map +1 -0
  37. package/dist/paths.js +38 -0
  38. package/dist/realpath.d.ts +9 -0
  39. package/dist/realpath.d.ts.map +1 -0
  40. package/dist/realpath.js +72 -0
  41. package/dist/repoSearch.d.ts +46 -0
  42. package/dist/repoSearch.d.ts.map +1 -0
  43. package/dist/repoSearch.js +350 -0
  44. package/dist/repoSearchEntries.d.ts +15 -0
  45. package/dist/repoSearchEntries.d.ts.map +1 -0
  46. package/dist/repoSearchEntries.js +106 -0
  47. package/dist/repoSearchLineSelection.d.ts +18 -0
  48. package/dist/repoSearchLineSelection.d.ts.map +1 -0
  49. package/dist/repoSearchLineSelection.js +43 -0
  50. package/dist/repoSearchMatchers.d.ts +8 -0
  51. package/dist/repoSearchMatchers.d.ts.map +1 -0
  52. package/dist/repoSearchMatchers.js +414 -0
  53. package/dist/repoSearchPolicy.d.ts +34 -0
  54. package/dist/repoSearchPolicy.d.ts.map +1 -0
  55. package/dist/repoSearchPolicy.js +342 -0
  56. package/dist/repoSearchRegexSafety.d.ts +2 -0
  57. package/dist/repoSearchRegexSafety.d.ts.map +1 -0
  58. package/dist/repoSearchRegexSafety.js +15 -0
  59. package/dist/repoSearchScan.d.ts +62 -0
  60. package/dist/repoSearchScan.d.ts.map +1 -0
  61. package/dist/repoSearchScan.js +292 -0
  62. package/dist/retrieval.d.ts +10 -0
  63. package/dist/retrieval.d.ts.map +1 -0
  64. package/dist/retrieval.js +74 -0
  65. package/dist/stableId.d.ts +4 -0
  66. package/dist/stableId.d.ts.map +1 -0
  67. package/dist/stableId.js +49 -0
  68. package/dist/structuralAdapters.d.ts +27 -0
  69. package/dist/structuralAdapters.d.ts.map +1 -0
  70. package/dist/structuralAdapters.js +87 -0
  71. package/dist/summary.d.ts +4 -0
  72. package/dist/summary.d.ts.map +1 -0
  73. package/dist/summary.js +54 -0
  74. package/dist/testSourcePairing.d.ts +3 -0
  75. package/dist/testSourcePairing.d.ts.map +1 -0
  76. package/dist/testSourcePairing.js +179 -0
  77. package/dist/types.d.ts +3 -0
  78. package/dist/types.d.ts.map +1 -0
  79. package/dist/types.js +4 -0
  80. package/dist/version.d.ts +2 -0
  81. package/dist/version.d.ts.map +1 -0
  82. package/dist/version.js +4 -0
  83. package/package.json +35 -0
@@ -0,0 +1,179 @@
1
+ // Test/source pairing adapter (Epic #177, Issue #180). Deterministic, pure-JS mapper that,
2
+ // given a workspace-relative path or a bare symbol name, locates the paired test (or paired
3
+ // source) file using fixed name conventions. Output normalized to EvidenceAtom via the shared
4
+ // buildAtom helper. Stays within ADR-0019 rule 3b: imports only @oscharko-dev/keiko-contracts,
5
+ // sibling workspace modules, and Node stdlib (node:crypto).
6
+ import { createHash } from "node:crypto";
7
+ import { resolveWithinWorkspace } from "./paths.js";
8
+ import { assertContainedRealPath } from "./realpath.js";
9
+ import { buildAtom, gatherCandidates } from "./repoSearchScan.js";
10
+ // Canonical fingerprint shared by every structural adapter: SHA-256({kind,text}) → 16 hex chars.
11
+ function queryFingerprint(query) {
12
+ const canonical = JSON.stringify({ kind: query.kind, text: query.text });
13
+ return createHash("sha256").update(canonical).digest("hex").slice(0, 16);
14
+ }
15
+ const PATH_EXT_RE = /\.(?:ts|tsx|js|jsx|mjs|cjs|mts|cts)$/;
16
+ const TEST_MARKER_RE = /\.(?:test|spec)\.(?:ts|tsx|js|jsx|mjs|cjs|mts|cts)$/;
17
+ function looksLikePath(text) {
18
+ return PATH_EXT_RE.test(text);
19
+ }
20
+ function extractExtension(path) {
21
+ const match = PATH_EXT_RE.exec(path);
22
+ if (match === null) {
23
+ return undefined;
24
+ }
25
+ return { stem: path.slice(0, match.index), ext: match[0] };
26
+ }
27
+ function basenameOf(stem) {
28
+ const slash = stem.lastIndexOf("/");
29
+ if (slash === -1) {
30
+ return { dir: "", base: stem };
31
+ }
32
+ return { dir: stem.slice(0, slash), base: stem.slice(slash + 1) };
33
+ }
34
+ // Map a source-shaped path to a prioritized list of candidate test paths.
35
+ function candidateTestsFor(path) {
36
+ const parts = extractExtension(path);
37
+ if (parts === undefined) {
38
+ return [];
39
+ }
40
+ const { stem, ext } = parts;
41
+ const { dir, base } = basenameOf(stem);
42
+ const out = [];
43
+ if (stem.startsWith("src/")) {
44
+ out.push(`tests/${stem.slice(4)}.test${ext}`);
45
+ }
46
+ out.push(`${stem}.test${ext}`);
47
+ out.push(`${stem}.spec${ext}`);
48
+ const nestedDir = dir === "" ? "__tests__" : `${dir}/__tests__`;
49
+ out.push(`${nestedDir}/${base}.test${ext}`);
50
+ return out;
51
+ }
52
+ // Map a test-shaped path back to its paired source path. The marker (".test." / ".spec.")
53
+ // and trailing extension are stripped to recover the stem; conventions are inverted to
54
+ // produce candidates in priority order.
55
+ function candidateSourcesFor(path) {
56
+ const match = TEST_MARKER_RE.exec(path);
57
+ if (match === null) {
58
+ return [];
59
+ }
60
+ const stem = path.slice(0, match.index);
61
+ const extWithDot = match[0].slice(match[0].lastIndexOf("."));
62
+ const { dir, base } = basenameOf(stem);
63
+ const out = [];
64
+ if (stem.startsWith("tests/")) {
65
+ out.push(`src/${stem.slice(6)}${extWithDot}`);
66
+ }
67
+ if (dir.endsWith("/__tests__")) {
68
+ out.push(`${dir.slice(0, -"/__tests__".length)}/${base}${extWithDot}`);
69
+ }
70
+ else if (dir === "__tests__") {
71
+ out.push(`${base}${extWithDot}`);
72
+ }
73
+ out.push(`${stem}${extWithDot}`);
74
+ return Array.from(new Set(out));
75
+ }
76
+ function isAllowedPath(ctx, relativePath) {
77
+ return ctx.allowedPaths === undefined || ctx.allowedPaths.has(relativePath);
78
+ }
79
+ function firstExistingPair(ctx, candidates) {
80
+ for (const candidate of candidates) {
81
+ if (!isAllowedPath(ctx, candidate)) {
82
+ continue;
83
+ }
84
+ const abs = resolveWithinWorkspace(ctx.scope.workspace.root, candidate);
85
+ assertContainedRealPath(ctx.fs, ctx.scope.workspace.root, abs, "scope");
86
+ if (ctx.fs.exists(abs)) {
87
+ return candidate;
88
+ }
89
+ }
90
+ return undefined;
91
+ }
92
+ function emitPairAtom(ctx, pairedPath) {
93
+ return buildAtom({
94
+ scopeId: ctx.scope.scopeId,
95
+ scopePath: pairedPath,
96
+ lineRange: undefined,
97
+ provenanceKind: "structural",
98
+ tool: "test-source-pairing",
99
+ queryFingerprint: ctx.fingerprint,
100
+ score: 0.8,
101
+ emittedAtMs: ctx.nowMs(),
102
+ });
103
+ }
104
+ function pairForPath(ctx, path) {
105
+ const isTest = TEST_MARKER_RE.test(path);
106
+ const candidates = isTest ? candidateSourcesFor(path) : candidateTestsFor(path);
107
+ const found = firstExistingPair(ctx, candidates);
108
+ return found === undefined ? undefined : emitPairAtom(ctx, found);
109
+ }
110
+ function pathsForSymbol(ctx, symbol, limits) {
111
+ const lowered = symbol.toLowerCase();
112
+ const out = [];
113
+ const files = ctx.allowedPaths === undefined
114
+ ? gatherCandidates(ctx.scope, limits, ctx.fs).files.map((file) => file.relativePath)
115
+ : [...ctx.allowedPaths];
116
+ for (const relativePath of files) {
117
+ const parts = extractExtension(relativePath);
118
+ if (parts === undefined) {
119
+ continue;
120
+ }
121
+ const base = basenameOf(parts.stem).base.replace(/\.(?:test|spec)$/, "");
122
+ if (base.toLowerCase() === lowered) {
123
+ out.push(relativePath);
124
+ }
125
+ }
126
+ return out;
127
+ }
128
+ function allowedPathsForScope(scope, limits, fs) {
129
+ if (scope.relativePaths.length === 0) {
130
+ return undefined;
131
+ }
132
+ return new Set(gatherCandidates(scope, limits, fs).files.map((file) => file.relativePath));
133
+ }
134
+ function inputsForQuery(ctx, query, limits) {
135
+ if (!looksLikePath(query.text)) {
136
+ return pathsForSymbol(ctx, query.text, limits);
137
+ }
138
+ return isAllowedPath(ctx, query.text) ? [query.text] : [];
139
+ }
140
+ export const testSourcePairingAdapter = {
141
+ name: "test-source-pairing",
142
+ isAvailable: () => Promise.resolve(true),
143
+ lookup: (scope, query, limits, fs, deps) => {
144
+ // Wrap the synchronous body so that throws from assertContainedRealPath surface as a
145
+ // rejected Promise (which the registry runner and `await expect(...).rejects.…` tests
146
+ // can observe). Without this wrapper the throw escapes the call site before the Promise
147
+ // is built.
148
+ try {
149
+ return Promise.resolve(runLookup(scope, query, limits, fs, deps));
150
+ }
151
+ catch (err) {
152
+ return Promise.reject(err instanceof Error ? err : new Error(String(err)));
153
+ }
154
+ },
155
+ };
156
+ function runLookup(scope, query, limits, fs, deps) {
157
+ if (query.kind !== "natural-language" && query.kind !== "exact-symbol") {
158
+ return [];
159
+ }
160
+ const ctx = {
161
+ scope,
162
+ fs,
163
+ nowMs: deps?.nowMs ?? Date.now,
164
+ fingerprint: queryFingerprint(query),
165
+ allowedPaths: allowedPathsForScope(scope, limits, fs),
166
+ };
167
+ const inputs = inputsForQuery(ctx, query, limits);
168
+ const atoms = [];
169
+ for (const input of inputs) {
170
+ if (atoms.length >= limits.maxMatchesReturned) {
171
+ break;
172
+ }
173
+ const atom = pairForPath(ctx, input);
174
+ if (atom !== undefined) {
175
+ atoms.push(atom);
176
+ }
177
+ }
178
+ return atoms;
179
+ }
@@ -0,0 +1,3 @@
1
+ export type { WorkspaceLanguage, TestFramework, WorkspaceInfo, DiscoveredFile, DiscoveryOptions, DiscoveryStats, ReadOptions, FileContent, SelectionReason, ContextRequest, ContextEntry, ContextPack, ContextEntrySummary, ContextPackSummary, WorkspaceSummary, AuditEntry, AuditSummary, } from "@oscharko-dev/keiko-contracts";
2
+ export { DEFAULT_DISCOVERY_OPTIONS, DEFAULT_READ_OPTIONS, SELECTION_REASON_PRIORITY, DEFAULT_CONTEXT_REQUEST, } from "@oscharko-dev/keiko-contracts";
3
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAIA,YAAY,EACV,iBAAiB,EACjB,aAAa,EACb,aAAa,EACb,cAAc,EACd,gBAAgB,EAChB,cAAc,EACd,WAAW,EACX,WAAW,EACX,eAAe,EACf,cAAc,EACd,YAAY,EACZ,WAAW,EACX,mBAAmB,EACnB,kBAAkB,EAClB,gBAAgB,EAChB,UAAU,EACV,YAAY,GACb,MAAM,+BAA+B,CAAC;AACvC,OAAO,EACL,yBAAyB,EACzB,oBAAoB,EACpB,yBAAyB,EACzB,uBAAuB,GACxB,MAAM,+BAA+B,CAAC"}
package/dist/types.js ADDED
@@ -0,0 +1,4 @@
1
+ // Re-export shim: workspace contract types live in @oscharko-dev/keiko-contracts (issue #158).
2
+ // `verbatimModuleSyntax` is on, so type-only names use `export type` and value-emitting frozen
3
+ // tables use `export`.
4
+ export { DEFAULT_DISCOVERY_OPTIONS, DEFAULT_READ_OPTIONS, SELECTION_REASON_PRIORITY, DEFAULT_CONTEXT_REQUEST, } from "@oscharko-dev/keiko-contracts";
@@ -0,0 +1,2 @@
1
+ export declare const KEIKO_WORKSPACE_VERSION: "0.3.0";
2
+ //# sourceMappingURL=version.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"version.d.ts","sourceRoot":"","sources":["../src/version.ts"],"names":[],"mappings":"AAGA,eAAO,MAAM,uBAAuB,EAAG,OAAgB,CAAC"}
@@ -0,0 +1,4 @@
1
+ // Version identifier for the workspace package. Pattern matches keiko-contracts /
2
+ // keiko-security / keiko-model-gateway: keep the literal type via `as const` so
3
+ // downstream assertions can pin on the exact string.
4
+ export const KEIKO_WORKSPACE_VERSION = "0.3.0";
package/package.json ADDED
@@ -0,0 +1,35 @@
1
+ {
2
+ "name": "@oscharko-dev/keiko-workspace",
3
+ "version": "0.2.0",
4
+ "type": "module",
5
+ "license": "Apache-2.0",
6
+ "description": "Internal workspace package: Keiko repository context and workspace access — detection, safe reads, path containment, deny/ignore rules, context packs, retrieval, and summaries. Not published independently.",
7
+ "main": "./dist/index.js",
8
+ "types": "./dist/index.d.ts",
9
+ "exports": {
10
+ ".": {
11
+ "types": "./dist/index.d.ts",
12
+ "import": "./dist/index.js"
13
+ },
14
+ "./internal/fs": {
15
+ "types": "./dist/fs.d.ts",
16
+ "import": "./dist/fs.js"
17
+ }
18
+ },
19
+ "scripts": {
20
+ "build": "tsc -b tsconfig.json",
21
+ "typecheck": "tsc -b tsconfig.json",
22
+ "test": "vitest run"
23
+ },
24
+ "files": [
25
+ "dist"
26
+ ],
27
+ "sideEffects": false,
28
+ "engines": {
29
+ "node": ">=22"
30
+ },
31
+ "dependencies": {
32
+ "@oscharko-dev/keiko-contracts": "0.2.0",
33
+ "@oscharko-dev/keiko-security": "0.2.0"
34
+ }
35
+ }