@oscharko-dev/keiko-memory-capture 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 (47) hide show
  1. package/dist/.tsbuildinfo +1 -0
  2. package/dist/_constants.d.ts +2 -0
  3. package/dist/_constants.d.ts.map +1 -0
  4. package/dist/_constants.js +6 -0
  5. package/dist/_envelopes.d.ts +30 -0
  6. package/dist/_envelopes.d.ts.map +1 -0
  7. package/dist/_envelopes.js +67 -0
  8. package/dist/capture-safety.d.ts +4 -0
  9. package/dist/capture-safety.d.ts.map +1 -0
  10. package/dist/capture-safety.js +17 -0
  11. package/dist/capture.d.ts +4 -0
  12. package/dist/capture.d.ts.map +1 -0
  13. package/dist/capture.js +66 -0
  14. package/dist/errors.d.ts +6 -0
  15. package/dist/errors.d.ts.map +1 -0
  16. package/dist/errors.js +18 -0
  17. package/dist/index.d.ts +7 -0
  18. package/dist/index.d.ts.map +1 -0
  19. package/dist/index.js +14 -0
  20. package/dist/intent-ambient.d.ts +3 -0
  21. package/dist/intent-ambient.d.ts.map +1 -0
  22. package/dist/intent-ambient.js +112 -0
  23. package/dist/intent-explicit.d.ts +6 -0
  24. package/dist/intent-explicit.d.ts.map +1 -0
  25. package/dist/intent-explicit.js +204 -0
  26. package/dist/intent-workflow.d.ts +3 -0
  27. package/dist/intent-workflow.d.ts.map +1 -0
  28. package/dist/intent-workflow.js +69 -0
  29. package/dist/policy.d.ts +12 -0
  30. package/dist/policy.d.ts.map +1 -0
  31. package/dist/policy.js +43 -0
  32. package/dist/salience.d.ts +13 -0
  33. package/dist/salience.d.ts.map +1 -0
  34. package/dist/salience.js +268 -0
  35. package/dist/scope-inference.d.ts +9 -0
  36. package/dist/scope-inference.d.ts.map +1 -0
  37. package/dist/scope-inference.js +45 -0
  38. package/dist/secret-patterns.d.ts +3 -0
  39. package/dist/secret-patterns.d.ts.map +1 -0
  40. package/dist/secret-patterns.js +124 -0
  41. package/dist/types.d.ts +61 -0
  42. package/dist/types.d.ts.map +1 -0
  43. package/dist/types.js +6 -0
  44. package/dist/version.d.ts +2 -0
  45. package/dist/version.d.ts.map +1 -0
  46. package/dist/version.js +1 -0
  47. package/package.json +31 -0
@@ -0,0 +1,45 @@
1
+ // Scope inference for keiko-memory-capture. Fail-closed: when the requested scope kind requires
2
+ // a coordinate (project/workspace/workflow) that is absent from the CaptureContext, the helper
3
+ // returns `null` so the top-level capture function emits a `scope-not-resolvable` rejection
4
+ // rather than silently downgrading to a less-specific scope (which would leak a project-scoped
5
+ // memory into the user's global view).
6
+ // When no explicit scopeKind is supplied, pick the most specific coordinate available on the
7
+ // context. Precedence: project > workspace > workflow > user. This matches the user mental
8
+ // model that captures made INSIDE a project are project-scoped by default.
9
+ function pickImplicitScopeKind(context) {
10
+ if (context.projectId !== undefined) {
11
+ return "project";
12
+ }
13
+ if (context.workspaceId !== undefined) {
14
+ return "workspace";
15
+ }
16
+ if (context.workflowDefinitionId !== undefined) {
17
+ return "workflow";
18
+ }
19
+ return "user";
20
+ }
21
+ function resolveExplicitScope(kind, context, allowGlobal) {
22
+ if (kind === "global") {
23
+ return allowGlobal ? { kind: "global" } : null;
24
+ }
25
+ if (kind === "user") {
26
+ return { kind: "user", userId: context.userId };
27
+ }
28
+ if (kind === "project") {
29
+ return context.projectId === undefined
30
+ ? null
31
+ : { kind: "project", projectId: context.projectId };
32
+ }
33
+ if (kind === "workspace") {
34
+ return context.workspaceId === undefined
35
+ ? null
36
+ : { kind: "workspace", workspaceId: context.workspaceId };
37
+ }
38
+ return context.workflowDefinitionId === undefined
39
+ ? null
40
+ : { kind: "workflow", workflowDefinitionId: context.workflowDefinitionId };
41
+ }
42
+ export function inferScopeFromContext(context, options) {
43
+ const kind = options.scopeKind ?? pickImplicitScopeKind(context);
44
+ return resolveExplicitScope(kind, context, options.allowGlobalScope ?? false);
45
+ }
@@ -0,0 +1,3 @@
1
+ import type { RejectionReason } from "./errors.js";
2
+ export declare function scanForSecrets(value: string, customerIdentifierMatchers?: readonly RegExp[]): RejectionReason | null;
3
+ //# sourceMappingURL=secret-patterns.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"secret-patterns.d.ts","sourceRoot":"","sources":["../src/secret-patterns.ts"],"names":[],"mappings":"AAmBA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAoGnD,wBAAgB,cAAc,CAC5B,KAAK,EAAE,MAAM,EACb,0BAA0B,GAAE,SAAS,MAAM,EAAO,GACjD,eAAe,GAAG,IAAI,CAiBxB"}
@@ -0,0 +1,124 @@
1
+ // Secret + private-data rejection scanner for keiko-memory-capture (Epic #204 child #207).
2
+ //
3
+ // This module is the WIDE secret-rejection net: it extends the narrow audit-summary heuristic
4
+ // `looksLikeSecretShape` (keiko-contracts/memory-validation.ts) with patterns the capture layer
5
+ // owns — opaque Bearer tokens, URL-embedded credentials, form-encoded password/secret/api_key/
6
+ // token assignments, and well-known credential-store file paths. The wider net is appropriate
7
+ // HERE (write-side gate, false positives reject a memory which the user can rephrase) but NOT
8
+ // at audit-time (where a false positive would unnecessarily mask an audit summary).
9
+ //
10
+ // ReDoS safety: every pattern is a single linear character class with one bounded or open
11
+ // quantifier — no nesting, no `(a+)+` style. Matches CodeQL js/polynomial-redos conventions
12
+ // followed in keiko-security/redaction.ts.
13
+ //
14
+ // The return value is the typed RejectionReason class. The matched substring is intentionally
15
+ // NOT returned: the rejection path itself must not leak the candidate's content (capture is the
16
+ // PRIMARY secret-prevention boundary; even the rejection notice is a redaction-sensitive
17
+ // surface). Callers render a generic "this looked like a credential" message keyed off the
18
+ // reason class.
19
+ // ─── Credential-shape patterns (extends looksLikeSecretShape) ────────────────
20
+ const CREDENTIAL_SHAPE_PATTERNS = [
21
+ // Parity with looksLikeSecretShape: sk-, AKIA, gh[pousr]_, xox[abporsu]-, JWT, PEM, digit runs.
22
+ /\bsk-[A-Za-z0-9_-]{20,}\b/,
23
+ /\bAKIA[0-9A-Z]{16}\b/,
24
+ /\bgh[pousr]_[A-Za-z0-9]{36,}\b/,
25
+ /\bxox[abporsu]-[A-Za-z0-9-]{10,}\b/,
26
+ /\beyJ[A-Za-z0-9_-]{8,}\.[A-Za-z0-9_-]{8,}\.[A-Za-z0-9_-]{8,}\b/,
27
+ /-----BEGIN [A-Z ]*PRIVATE KEY-----/,
28
+ /\b\d{13,19}\b/,
29
+ // Capture-layer extensions:
30
+ // Opaque Bearer tokens (any non-whitespace token after "Bearer "). looksLikeSecretShape
31
+ // intentionally skips this because audit summaries may legitimately mention the word "Bearer"
32
+ // with a placeholder; capture is stricter because a real Bearer in a memory body is almost
33
+ // never legitimate.
34
+ /\bBearer\s+[A-Za-z0-9._~+/=-]+/i,
35
+ // URL-embedded basic-auth credentials.
36
+ /\bhttps?:\/\/[^\s/:@]+:[^\s/:@]+@/i,
37
+ // Form-encoded credential assignments. Each is a single non-nested capture; the value run
38
+ // stops at whitespace or common delimiters so the quantifier can't backtrack.
39
+ /\bpassword\s*[=:]\s*[^\s,;"'`&]+/i,
40
+ /\bsecret\s*[=:]\s*[^\s,;"'`&]+/i,
41
+ /\bapi[_-]?key\s*[=:]\s*[^\s,;"'`&]+/i,
42
+ /\btoken\s*[=:]\s*[^\s,;"'`&]+/i,
43
+ ];
44
+ // ─── Credential-store file paths ─────────────────────────────────────────────
45
+ // Conservative, case-insensitive, anchored on the credential-store basename (after the last
46
+ // slash). A bare mention of a path like `~/.ssh/id_rsa` or `.env.production` is a strong signal
47
+ // the user is pasting an artefact they shouldn't be memorising.
48
+ const CREDENTIAL_PATH_PATTERNS = [
49
+ // SSH private keys: id_rsa, id_ed25519, id_ecdsa, id_dsa, id_<custom>. Match any path segment.
50
+ /\.ssh\/id_[A-Za-z0-9_-]+/i,
51
+ // AWS credentials file.
52
+ /\.aws\/credentials\b/i,
53
+ // npm rc (auth tokens), gcloud credentials, k8s configs, common dotfile credential stores.
54
+ /(^|[\s/])\.npmrc\b/i,
55
+ // .env and .env.<environment>.
56
+ /(^|[\s/])\.env(\.[A-Za-z0-9_-]+)?\b/i,
57
+ ];
58
+ const URL_CANDIDATE_RE = /\bhttps?:\/\/[^\s"'`<>]+/gi;
59
+ const PROVIDER_CONTEXT_RE = /\b(provider|gateway|base\s+url|base-url|api\s+endpoint|endpoint|openai-compatible)\b/i;
60
+ const ISO_LOG_TIMESTAMP_RE = /\b\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d{1,6})?Z\b/;
61
+ const LOG_SEVERITY_RE = /\b(trace|debug|info|warn(?:ing)?|error|fatal)\b/i;
62
+ const STACK_TRACE_MARKER_RE = /\b(stack trace|traceback|exception stack)\b/i;
63
+ const STACK_FRAME_RE = /\bat\s+[A-Za-z_$][\w.$<>]*(?:\s+\[[^\]]+\])?\([^)\n]*\)/g;
64
+ function matchesAny(value, patterns) {
65
+ for (const pattern of patterns) {
66
+ if (pattern.test(value)) {
67
+ return true;
68
+ }
69
+ }
70
+ return false;
71
+ }
72
+ function looksLikeProviderBaseUrl(value) {
73
+ for (const match of value.matchAll(URL_CANDIDATE_RE)) {
74
+ const raw = match[0];
75
+ const index = match.index;
76
+ let parsed;
77
+ try {
78
+ parsed = new URL(raw);
79
+ }
80
+ catch {
81
+ continue;
82
+ }
83
+ if (parsed.protocol !== "http:" && parsed.protocol !== "https:") {
84
+ continue;
85
+ }
86
+ const normalizedPath = parsed.pathname.replace(/\/+$/u, "");
87
+ const hasOpenAiBasePath = normalizedPath === "/v1" ||
88
+ normalizedPath === "/openai/v1" ||
89
+ normalizedPath.endsWith("/openai/v1");
90
+ const snippet = value.slice(Math.max(0, index - 48), Math.min(value.length, index + raw.length + 24));
91
+ if (PROVIDER_CONTEXT_RE.test(snippet) || hasOpenAiBasePath) {
92
+ return true;
93
+ }
94
+ }
95
+ return false;
96
+ }
97
+ function looksLikeRawLog(value) {
98
+ const stackFrameCount = value.match(STACK_FRAME_RE)?.length ?? 0;
99
+ const hasSeverityWithTimestamp = LOG_SEVERITY_RE.test(value) && ISO_LOG_TIMESTAMP_RE.test(value);
100
+ const hasExplicitStackTrace = STACK_TRACE_MARKER_RE.test(value) && stackFrameCount >= 1;
101
+ return hasSeverityWithTimestamp || hasExplicitStackTrace || stackFrameCount >= 2;
102
+ }
103
+ // Returns the typed rejection class if `value` looks like a secret, credential-store path, or
104
+ // customer-identifier match — otherwise `null`. The scan is total: it runs every pattern class
105
+ // in a fixed precedence (credential-shape > credential-path > customer-identifier) so two
106
+ // patterns firing on the same string produce a deterministic reason class.
107
+ export function scanForSecrets(value, customerIdentifierMatchers = []) {
108
+ if (matchesAny(value, CREDENTIAL_SHAPE_PATTERNS)) {
109
+ return "credential-shape";
110
+ }
111
+ if (matchesAny(value, CREDENTIAL_PATH_PATTERNS)) {
112
+ return "private-credential-path";
113
+ }
114
+ if (looksLikeProviderBaseUrl(value)) {
115
+ return "provider-base-url";
116
+ }
117
+ if (looksLikeRawLog(value)) {
118
+ return "raw-log-content";
119
+ }
120
+ if (matchesAny(value, customerIdentifierMatchers)) {
121
+ return "customer-identifier";
122
+ }
123
+ return null;
124
+ }
@@ -0,0 +1,61 @@
1
+ import type { ConversationId, MemoryForget, MemoryId, MemoryProposal, MemoryProposalId, MemoryScope, MemoryScopeKind, MemorySensitivity, MemorySupersession, MemoryUpdate, ProjectId, UserId, WorkflowDefinitionId, WorkflowRunId, WorkspaceId } from "@oscharko-dev/keiko-contracts/memory";
2
+ import type { RejectionReason } from "./errors.js";
3
+ export interface CaptureContext {
4
+ readonly userId: UserId;
5
+ readonly workspaceId?: WorkspaceId;
6
+ readonly projectId?: ProjectId;
7
+ readonly workflowDefinitionId?: WorkflowDefinitionId;
8
+ readonly sourceWorkflowRunId?: WorkflowRunId;
9
+ readonly conversationId?: ConversationId;
10
+ readonly nowMs: number;
11
+ readonly newMemoryId: () => MemoryId;
12
+ readonly newProposalId: () => MemoryProposalId;
13
+ }
14
+ export type CaptureMemoryResolver = (target: string, scope: MemoryScope) => readonly MemoryId[];
15
+ export interface CapturePolicyOptions {
16
+ readonly customerIdentifierMatchers?: readonly RegExp[];
17
+ readonly defaultSensitivity?: MemorySensitivity;
18
+ readonly resolver?: CaptureMemoryResolver;
19
+ readonly allowGlobalScope?: boolean;
20
+ readonly scopeKind?: MemoryScopeKind;
21
+ readonly maxBodyChars?: number;
22
+ }
23
+ export interface WorkflowOutcomeInput {
24
+ readonly runId: WorkflowRunId;
25
+ readonly outcomeKind: "success" | "corrected" | "failed";
26
+ readonly structuredReport: string;
27
+ readonly capturedAt: number;
28
+ }
29
+ export type CaptureOutcome = {
30
+ readonly kind: "candidate";
31
+ readonly proposal: MemoryProposal;
32
+ readonly requiresApproval: boolean;
33
+ } | {
34
+ readonly kind: "update";
35
+ readonly operation: MemoryUpdate;
36
+ } | {
37
+ readonly kind: "forget";
38
+ readonly operation: MemoryForget;
39
+ readonly requiresConfirmation: boolean;
40
+ } | {
41
+ readonly kind: "supersession";
42
+ readonly operation: MemorySupersession;
43
+ } | {
44
+ readonly kind: "rejected";
45
+ readonly reason: RejectionReason;
46
+ };
47
+ export type MemoryScopeKindHint = Extract<MemoryScopeKind, "user" | "project" | "workspace">;
48
+ export interface SalienceInput {
49
+ readonly userText: string;
50
+ readonly assistantText?: string;
51
+ readonly existingBodies: readonly string[];
52
+ readonly context: CaptureContext;
53
+ readonly policy?: CapturePolicyOptions;
54
+ }
55
+ export interface SalienceDeps {
56
+ readonly callModel: (system: string, user: string) => Promise<string>;
57
+ readonly now: () => number;
58
+ readonly newMemoryId: () => MemoryId;
59
+ readonly newProposalId: () => MemoryProposalId;
60
+ }
61
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
package/dist/types.js ADDED
@@ -0,0 +1,6 @@
1
+ // Public types for keiko-memory-capture (Epic #204 child #207).
2
+ //
3
+ // Capture is purely deterministic: the caller injects clock (`nowMs`) and id factories (`newId`,
4
+ // `newProposalId`) via `CaptureContext`, so the same input + context produces a byte-identical
5
+ // outcome. This keeps the evaluation harness (#215) and audit ledger (#214) reproducible.
6
+ export {};
@@ -0,0 +1,2 @@
1
+ export declare const KEIKO_MEMORY_CAPTURE_VERSION: "0.1.0";
2
+ //# sourceMappingURL=version.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"version.d.ts","sourceRoot":"","sources":["../src/version.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,4BAA4B,EAAG,OAAgB,CAAC"}
@@ -0,0 +1 @@
1
+ export const KEIKO_MEMORY_CAPTURE_VERSION = "0.1.0";
package/package.json ADDED
@@ -0,0 +1,31 @@
1
+ {
2
+ "name": "@oscharko-dev/keiko-memory-capture",
3
+ "version": "0.2.0",
4
+ "type": "module",
5
+ "license": "Apache-2.0",
6
+ "description": "MemoriaViva — Internal memory-capture package: governed capture policy gate that turns raw user text and reviewed workflow outcomes into MemoryProposal / MemoryUpdate / MemoryForget / MemorySupersession envelopes. PRIMARY secret-prevention boundary (defence-in-depth on top of looksLikeSecretShape in keiko-contracts). Pure functions only; no IO, no clock, no randomness (caller supplies nowMs and newId via CaptureContext). ADR-0019 direction rule 3g (capture may depend only on keiko-contracts and keiko-security). 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
+ },
15
+ "scripts": {
16
+ "build": "tsc -b tsconfig.json",
17
+ "typecheck": "tsc -b tsconfig.json",
18
+ "test": "vitest run"
19
+ },
20
+ "files": [
21
+ "dist"
22
+ ],
23
+ "sideEffects": false,
24
+ "engines": {
25
+ "node": ">=22"
26
+ },
27
+ "dependencies": {
28
+ "@oscharko-dev/keiko-contracts": "0.2.0",
29
+ "@oscharko-dev/keiko-security": "0.2.0"
30
+ }
31
+ }