@keel_flow/learn 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.
- package/LICENSE +21 -0
- package/dist/apply.d.ts +20 -0
- package/dist/apply.d.ts.map +1 -0
- package/dist/apply.js +89 -0
- package/dist/apply.js.map +1 -0
- package/dist/diff-gen.d.ts +20 -0
- package/dist/diff-gen.d.ts.map +1 -0
- package/dist/diff-gen.js +63 -0
- package/dist/diff-gen.js.map +1 -0
- package/dist/index.d.ts +11 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +6 -0
- package/dist/index.js.map +1 -0
- package/dist/proposals.d.ts +19 -0
- package/dist/proposals.d.ts.map +1 -0
- package/dist/proposals.js +26 -0
- package/dist/proposals.js.map +1 -0
- package/dist/queue.d.ts +35 -0
- package/dist/queue.d.ts.map +1 -0
- package/dist/queue.js +84 -0
- package/dist/queue.js.map +1 -0
- package/dist/recurrence.d.ts +14 -0
- package/dist/recurrence.d.ts.map +1 -0
- package/dist/recurrence.js +63 -0
- package/dist/recurrence.js.map +1 -0
- package/package.json +42 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 jglasskatz
|
|
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/dist/apply.d.ts
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { LearningProposal } from "@keel_flow/schema";
|
|
2
|
+
export interface ApplyProposalInput {
|
|
3
|
+
proposal: LearningProposal;
|
|
4
|
+
diff: string;
|
|
5
|
+
cwd: string;
|
|
6
|
+
verifyFn?: () => Promise<{
|
|
7
|
+
exitCode: number;
|
|
8
|
+
}>;
|
|
9
|
+
branchPrefix?: string;
|
|
10
|
+
}
|
|
11
|
+
export interface ApplyProposalResult {
|
|
12
|
+
branch: string;
|
|
13
|
+
applied: boolean;
|
|
14
|
+
verifyExitCode: number | null;
|
|
15
|
+
deferred: boolean;
|
|
16
|
+
reason?: string;
|
|
17
|
+
}
|
|
18
|
+
export declare function inferBranchName(proposalId: string, prefix?: string): string;
|
|
19
|
+
export declare function applyAccepted(input: ApplyProposalInput): Promise<ApplyProposalResult>;
|
|
20
|
+
//# sourceMappingURL=apply.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"apply.d.ts","sourceRoot":"","sources":["../src/apply.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AAG1D,MAAM,WAAW,kBAAkB;IACjC,QAAQ,EAAE,gBAAgB,CAAC;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,MAAM,CAAC;IACZ,QAAQ,CAAC,EAAE,MAAM,OAAO,CAAC;QAAE,QAAQ,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAC/C,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,MAAM,WAAW,mBAAmB;IAClC,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,OAAO,CAAC;IACjB,cAAc,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,QAAQ,EAAE,OAAO,CAAC;IAClB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAWD,wBAAgB,eAAe,CAAC,UAAU,EAAE,MAAM,EAAE,MAAM,SAAe,GAAG,MAAM,CAEjF;AAED,wBAAsB,aAAa,CACjC,KAAK,EAAE,kBAAkB,GACxB,OAAO,CAAC,mBAAmB,CAAC,CA8E9B"}
|
package/dist/apply.js
ADDED
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import { promises as fs } from "node:fs";
|
|
2
|
+
import { spawnSync } from "node:child_process";
|
|
3
|
+
import { join, resolve } from "node:path";
|
|
4
|
+
import { markStatus } from "./queue.js";
|
|
5
|
+
function git(args, cwd) {
|
|
6
|
+
const res = spawnSync("git", args, { cwd, encoding: "utf-8" });
|
|
7
|
+
return {
|
|
8
|
+
stdout: res.stdout ?? "",
|
|
9
|
+
stderr: res.stderr ?? "",
|
|
10
|
+
ok: res.status === 0,
|
|
11
|
+
};
|
|
12
|
+
}
|
|
13
|
+
export function inferBranchName(proposalId, prefix = "keel-learn") {
|
|
14
|
+
return `${prefix}/${proposalId.slice(0, 12)}`;
|
|
15
|
+
}
|
|
16
|
+
export async function applyAccepted(input) {
|
|
17
|
+
const cwd = resolve(input.cwd);
|
|
18
|
+
const branch = inferBranchName(input.proposal.id, input.branchPrefix);
|
|
19
|
+
// Capture the current branch so we can return to it on failure
|
|
20
|
+
const head = git(["rev-parse", "--abbrev-ref", "HEAD"], cwd);
|
|
21
|
+
const previousBranch = head.ok ? head.stdout.trim() : null;
|
|
22
|
+
// Create the new branch off HEAD
|
|
23
|
+
const create = git(["checkout", "-b", branch], cwd);
|
|
24
|
+
if (!create.ok) {
|
|
25
|
+
await markStatus(input.proposal.id, "deferred", cwd, {
|
|
26
|
+
note: `Could not create branch ${branch}: ${create.stderr.trim()}`,
|
|
27
|
+
});
|
|
28
|
+
return {
|
|
29
|
+
branch,
|
|
30
|
+
applied: false,
|
|
31
|
+
verifyExitCode: null,
|
|
32
|
+
deferred: true,
|
|
33
|
+
reason: `branch-create-failed`,
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
// Write the diff to a tmp file and apply
|
|
37
|
+
const tmpPath = join(cwd, `.keel-learn-${input.proposal.id}.patch`);
|
|
38
|
+
await fs.writeFile(tmpPath, input.diff.endsWith("\n") ? input.diff : input.diff + "\n", "utf-8");
|
|
39
|
+
const apply = git(["apply", "--whitespace=nowarn", tmpPath], cwd);
|
|
40
|
+
await fs.rm(tmpPath, { force: true });
|
|
41
|
+
if (!apply.ok) {
|
|
42
|
+
if (previousBranch)
|
|
43
|
+
git(["checkout", previousBranch], cwd);
|
|
44
|
+
git(["branch", "-D", branch], cwd);
|
|
45
|
+
await markStatus(input.proposal.id, "deferred", cwd, {
|
|
46
|
+
note: `git apply failed: ${apply.stderr.trim()}`,
|
|
47
|
+
});
|
|
48
|
+
return {
|
|
49
|
+
branch,
|
|
50
|
+
applied: false,
|
|
51
|
+
verifyExitCode: null,
|
|
52
|
+
deferred: true,
|
|
53
|
+
reason: "git-apply-failed",
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
// Run verify (injected for tests, otherwise no-op pass-through)
|
|
57
|
+
let verifyExitCode = null;
|
|
58
|
+
if (input.verifyFn) {
|
|
59
|
+
const v = await input.verifyFn();
|
|
60
|
+
verifyExitCode = v.exitCode;
|
|
61
|
+
}
|
|
62
|
+
// exitCode === 2 means critical violations per the verify-gate contract
|
|
63
|
+
if (verifyExitCode === 2) {
|
|
64
|
+
if (previousBranch)
|
|
65
|
+
git(["checkout", previousBranch], cwd);
|
|
66
|
+
await markStatus(input.proposal.id, "deferred", cwd, {
|
|
67
|
+
note: "verify gate flagged critical violations",
|
|
68
|
+
verifyExitCode,
|
|
69
|
+
});
|
|
70
|
+
return {
|
|
71
|
+
branch,
|
|
72
|
+
applied: true,
|
|
73
|
+
verifyExitCode,
|
|
74
|
+
deferred: true,
|
|
75
|
+
reason: "verify-critical-failure",
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
await markStatus(input.proposal.id, "accepted", cwd, {
|
|
79
|
+
note: `applied on branch ${branch}`,
|
|
80
|
+
...(verifyExitCode !== null ? { verifyExitCode } : {}),
|
|
81
|
+
});
|
|
82
|
+
return {
|
|
83
|
+
branch,
|
|
84
|
+
applied: true,
|
|
85
|
+
verifyExitCode,
|
|
86
|
+
deferred: false,
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
//# sourceMappingURL=apply.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"apply.js","sourceRoot":"","sources":["../src/apply.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { ModelProvider } from "@keel_flow/runtime";
|
|
2
|
+
import type { LearningProposal } from "@keel_flow/schema";
|
|
3
|
+
import type { ParsedSuggestion } from "@keel_flow/reflect";
|
|
4
|
+
export interface DiffGenInput {
|
|
5
|
+
proposal: LearningProposal;
|
|
6
|
+
suggestion: ParsedSuggestion;
|
|
7
|
+
cwd: string;
|
|
8
|
+
provider: ModelProvider;
|
|
9
|
+
model?: string;
|
|
10
|
+
/** Override the file the diff is applied to. Defaults to defaultTargetPath. */
|
|
11
|
+
targetPath?: string;
|
|
12
|
+
}
|
|
13
|
+
export interface DiffGenResult {
|
|
14
|
+
path: string;
|
|
15
|
+
diff: string;
|
|
16
|
+
unableToDiff: boolean;
|
|
17
|
+
reason?: string;
|
|
18
|
+
}
|
|
19
|
+
export declare function proposalToDiff(input: DiffGenInput): Promise<DiffGenResult>;
|
|
20
|
+
//# sourceMappingURL=diff-gen.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"diff-gen.d.ts","sourceRoot":"","sources":["../src/diff-gen.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACxD,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AAC1D,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAe3D,MAAM,WAAW,YAAY;IAC3B,QAAQ,EAAE,gBAAgB,CAAC;IAC3B,UAAU,EAAE,gBAAgB,CAAC;IAC7B,GAAG,EAAE,MAAM,CAAC;IACZ,QAAQ,EAAE,aAAa,CAAC;IACxB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,+EAA+E;IAC/E,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,YAAY,EAAE,OAAO,CAAC;IACtB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAOD,wBAAsB,cAAc,CAAC,KAAK,EAAE,YAAY,GAAG,OAAO,CAAC,aAAa,CAAC,CAgDhF"}
|
package/dist/diff-gen.js
ADDED
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { promises as fs } from "node:fs";
|
|
2
|
+
import { existsSync } from "node:fs";
|
|
3
|
+
import { resolve } from "node:path";
|
|
4
|
+
import { defaultTargetPath } from "./proposals.js";
|
|
5
|
+
const DIFF_SYSTEM_PROMPT = `You are the diff generator for Keel's learning loop.
|
|
6
|
+
|
|
7
|
+
Given a single proposed change description and the current contents of a target file, produce a unified diff (\`diff -u\` format) that applies the change.
|
|
8
|
+
|
|
9
|
+
Hard constraints:
|
|
10
|
+
- Emit ONLY the unified diff, no preamble, no closing remarks, no fences.
|
|
11
|
+
- Use the exact path supplied by the user as both \`---\` and \`+++\` paths (no a/ or b/ prefix).
|
|
12
|
+
- Preserve the file's surrounding context (3 context lines per hunk).
|
|
13
|
+
- Make the smallest change that accomplishes the proposal.
|
|
14
|
+
- Do not invent edits the proposal does not call for.
|
|
15
|
+
- If the proposal cannot be expressed as a sensible diff, emit a single-line comment \`# unable-to-diff: <reason>\` instead.`;
|
|
16
|
+
async function readTargetSafely(path) {
|
|
17
|
+
if (!existsSync(path))
|
|
18
|
+
return "";
|
|
19
|
+
return fs.readFile(path, "utf-8");
|
|
20
|
+
}
|
|
21
|
+
export async function proposalToDiff(input) {
|
|
22
|
+
const path = input.targetPath ?? defaultTargetPath({
|
|
23
|
+
cwd: input.cwd,
|
|
24
|
+
target: input.proposal.target,
|
|
25
|
+
});
|
|
26
|
+
const cwdAbs = resolve(input.cwd);
|
|
27
|
+
const relPath = path.startsWith(cwdAbs + "/") ? path.slice(cwdAbs.length + 1) : path;
|
|
28
|
+
const current = await readTargetSafely(path);
|
|
29
|
+
const userPrompt = `Target file: ${relPath}\n` +
|
|
30
|
+
`Target kind: ${input.proposal.target}\n` +
|
|
31
|
+
`Proposal title: ${input.suggestion.title}\n` +
|
|
32
|
+
`Proposal rationale: ${input.suggestion.rationale}\n` +
|
|
33
|
+
`Proposal change: ${input.suggestion.change}\n\n` +
|
|
34
|
+
`## Current file contents (first 12k chars)\n\n` +
|
|
35
|
+
`\`\`\`\n${current.slice(0, 12000)}\n\`\`\`\n\n` +
|
|
36
|
+
`Emit the unified diff now.`;
|
|
37
|
+
const res = await input.provider.generate({
|
|
38
|
+
system: DIFF_SYSTEM_PROMPT,
|
|
39
|
+
messages: [
|
|
40
|
+
{
|
|
41
|
+
role: "user",
|
|
42
|
+
content: [{ type: "text", text: userPrompt }],
|
|
43
|
+
},
|
|
44
|
+
],
|
|
45
|
+
maxTokens: 2048,
|
|
46
|
+
model: input.model ?? input.provider.defaultModel,
|
|
47
|
+
});
|
|
48
|
+
const text = res.content
|
|
49
|
+
.map((b) => (b.type === "text" ? b.text : ""))
|
|
50
|
+
.join("")
|
|
51
|
+
.trim();
|
|
52
|
+
const unableMatch = /^#\s*unable-to-diff:\s*(.*)$/m.exec(text);
|
|
53
|
+
if (unableMatch) {
|
|
54
|
+
return {
|
|
55
|
+
path,
|
|
56
|
+
diff: text,
|
|
57
|
+
unableToDiff: true,
|
|
58
|
+
reason: (unableMatch[1] ?? "").trim(),
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
return { path, diff: text, unableToDiff: false };
|
|
62
|
+
}
|
|
63
|
+
//# sourceMappingURL=diff-gen.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"diff-gen.js","sourceRoot":"","sources":["../src/diff-gen.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,IAAI,EAAE,EAAE,MAAM,SAAS,CAAC;AACzC,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AACrC,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAIpC,OAAO,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AAEnD,MAAM,kBAAkB,GAAG;;;;;;;;;;6HAUkG,CAAC;AAmB9H,KAAK,UAAU,gBAAgB,CAAC,IAAY;IAC1C,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC;QAAE,OAAO,EAAE,CAAC;IACjC,OAAO,EAAE,CAAC,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;AACpC,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,cAAc,CAAC,KAAmB;IACtD,MAAM,IAAI,GAAG,KAAK,CAAC,UAAU,IAAI,iBAAiB,CAAC;QACjD,GAAG,EAAE,KAAK,CAAC,GAAG;QACd,MAAM,EAAE,KAAK,CAAC,QAAQ,CAAC,MAAM;KAC9B,CAAC,CAAC;IACH,MAAM,MAAM,GAAG,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IAClC,MAAM,OAAO,GAAG,IAAI,CAAC,UAAU,CAAC,MAAM,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;IAErF,MAAM,OAAO,GAAG,MAAM,gBAAgB,CAAC,IAAI,CAAC,CAAC;IAE7C,MAAM,UAAU,GACd,gBAAgB,OAAO,IAAI;QAC3B,gBAAgB,KAAK,CAAC,QAAQ,CAAC,MAAM,IAAI;QACzC,mBAAmB,KAAK,CAAC,UAAU,CAAC,KAAK,IAAI;QAC7C,uBAAuB,KAAK,CAAC,UAAU,CAAC,SAAS,IAAI;QACrD,oBAAoB,KAAK,CAAC,UAAU,CAAC,MAAM,MAAM;QACjD,gDAAgD;QAChD,WAAW,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,KAAK,CAAC,cAAc;QAChD,4BAA4B,CAAC;IAE/B,MAAM,GAAG,GAAG,MAAM,KAAK,CAAC,QAAQ,CAAC,QAAQ,CAAC;QACxC,MAAM,EAAE,kBAAkB;QAC1B,QAAQ,EAAE;YACR;gBACE,IAAI,EAAE,MAAM;gBACZ,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,UAAU,EAAE,CAAC;aAC9C;SACF;QACD,SAAS,EAAE,IAAI;QACf,KAAK,EAAE,KAAK,CAAC,KAAK,IAAI,KAAK,CAAC,QAAQ,CAAC,YAAY;KAClD,CAAC,CAAC;IAEH,MAAM,IAAI,GAAG,GAAG,CAAC,OAAO;SACrB,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,KAAK,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;SAC7C,IAAI,CAAC,EAAE,CAAC;SACR,IAAI,EAAE,CAAC;IAEV,MAAM,WAAW,GAAG,+BAA+B,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAC/D,IAAI,WAAW,EAAE,CAAC;QAChB,OAAO;YACL,IAAI;YACJ,IAAI,EAAE,IAAI;YACV,YAAY,EAAE,IAAI;YAClB,MAAM,EAAE,CAAC,WAAW,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE;SACtC,CAAC;IACJ,CAAC;IAED,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,YAAY,EAAE,KAAK,EAAE,CAAC;AACnD,CAAC"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export { loadProposalsFromReflectionMarkdown, defaultTargetPath, } from "./proposals.js";
|
|
2
|
+
export type { LearningProposal, LearningTarget, LoadFromReflectionOptions, ProposalWithContext, TargetPathArgs, } from "./proposals.js";
|
|
3
|
+
export { proposalToDiff } from "./diff-gen.js";
|
|
4
|
+
export type { DiffGenInput, DiffGenResult } from "./diff-gen.js";
|
|
5
|
+
export { loadAllProposals, loadPending, loadEmerging, loadByStatus, readStatusLog, markStatus, currentStatus, learnLogPath, } from "./queue.js";
|
|
6
|
+
export type { ProposalRecord, StatusEvent } from "./queue.js";
|
|
7
|
+
export { gateProposals, promotedProposals, lessonKey, RECURRENCE_THRESHOLD, } from "./recurrence.js";
|
|
8
|
+
export type { GatedProposal, PromotionState } from "./recurrence.js";
|
|
9
|
+
export { applyAccepted, inferBranchName } from "./apply.js";
|
|
10
|
+
export type { ApplyProposalInput, ApplyProposalResult } from "./apply.js";
|
|
11
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,mCAAmC,EACnC,iBAAiB,GAClB,MAAM,gBAAgB,CAAC;AACxB,YAAY,EACV,gBAAgB,EAChB,cAAc,EACd,yBAAyB,EACzB,mBAAmB,EACnB,cAAc,GACf,MAAM,gBAAgB,CAAC;AAExB,OAAO,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAC/C,YAAY,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAEjE,OAAO,EACL,gBAAgB,EAChB,WAAW,EACX,YAAY,EACZ,YAAY,EACZ,aAAa,EACb,UAAU,EACV,aAAa,EACb,YAAY,GACb,MAAM,YAAY,CAAC;AACpB,YAAY,EAAE,cAAc,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAE9D,OAAO,EACL,aAAa,EACb,iBAAiB,EACjB,SAAS,EACT,oBAAoB,GACrB,MAAM,iBAAiB,CAAC;AACzB,YAAY,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAErE,OAAO,EAAE,aAAa,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAC5D,YAAY,EAAE,kBAAkB,EAAE,mBAAmB,EAAE,MAAM,YAAY,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export { loadProposalsFromReflectionMarkdown, defaultTargetPath, } from "./proposals.js";
|
|
2
|
+
export { proposalToDiff } from "./diff-gen.js";
|
|
3
|
+
export { loadAllProposals, loadPending, loadEmerging, loadByStatus, readStatusLog, markStatus, currentStatus, learnLogPath, } from "./queue.js";
|
|
4
|
+
export { gateProposals, promotedProposals, lessonKey, RECURRENCE_THRESHOLD, } from "./recurrence.js";
|
|
5
|
+
export { applyAccepted, inferBranchName } from "./apply.js";
|
|
6
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,mCAAmC,EACnC,iBAAiB,GAClB,MAAM,gBAAgB,CAAC;AASxB,OAAO,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAG/C,OAAO,EACL,gBAAgB,EAChB,WAAW,EACX,YAAY,EACZ,YAAY,EACZ,aAAa,EACb,UAAU,EACV,aAAa,EACb,YAAY,GACb,MAAM,YAAY,CAAC;AAGpB,OAAO,EACL,aAAa,EACb,iBAAiB,EACjB,SAAS,EACT,oBAAoB,GACrB,MAAM,iBAAiB,CAAC;AAGzB,OAAO,EAAE,aAAa,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { LearningProposal, LearningTarget } from "@keel_flow/schema";
|
|
2
|
+
import { type ParsedSuggestion } from "@keel_flow/reflect";
|
|
3
|
+
export type { LearningProposal, LearningTarget } from "@keel_flow/schema";
|
|
4
|
+
export interface LoadFromReflectionOptions {
|
|
5
|
+
markdown: string;
|
|
6
|
+
sessionId?: string;
|
|
7
|
+
createdAt?: string;
|
|
8
|
+
}
|
|
9
|
+
export declare function loadProposalsFromReflectionMarkdown(opts: LoadFromReflectionOptions): LearningProposal[];
|
|
10
|
+
export interface TargetPathArgs {
|
|
11
|
+
cwd: string;
|
|
12
|
+
target: LearningTarget;
|
|
13
|
+
}
|
|
14
|
+
export declare function defaultTargetPath(args: TargetPathArgs): string;
|
|
15
|
+
export interface ProposalWithContext extends LearningProposal {
|
|
16
|
+
suggestion: ParsedSuggestion;
|
|
17
|
+
reflectionPath: string;
|
|
18
|
+
}
|
|
19
|
+
//# sourceMappingURL=proposals.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"proposals.d.ts","sourceRoot":"","sources":["../src/proposals.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,gBAAgB,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAC1E,OAAO,EAGL,KAAK,gBAAgB,EACtB,MAAM,oBAAoB,CAAC;AAE5B,YAAY,EAAE,gBAAgB,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAE1E,MAAM,WAAW,yBAAyB;IACxC,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,wBAAgB,mCAAmC,CACjD,IAAI,EAAE,yBAAyB,GAC9B,gBAAgB,EAAE,CASpB;AAED,MAAM,WAAW,cAAc;IAC7B,GAAG,EAAE,MAAM,CAAC;IACZ,MAAM,EAAE,cAAc,CAAC;CACxB;AAED,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,cAAc,GAAG,MAAM,CAa9D;AAED,MAAM,WAAW,mBAAoB,SAAQ,gBAAgB;IAC3D,UAAU,EAAE,gBAAgB,CAAC;IAC7B,cAAc,EAAE,MAAM,CAAC;CACxB"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { homedir } from "node:os";
|
|
2
|
+
import { join, resolve } from "node:path";
|
|
3
|
+
import { parseSuggestionsFromMarkdown, proposalFromSuggestion, } from "@keel_flow/reflect";
|
|
4
|
+
export function loadProposalsFromReflectionMarkdown(opts) {
|
|
5
|
+
const suggestions = parseSuggestionsFromMarkdown(opts.markdown);
|
|
6
|
+
const sessionIds = opts.sessionId ? [opts.sessionId] : [];
|
|
7
|
+
return suggestions.map((s) => proposalFromSuggestion(s, {
|
|
8
|
+
sessionIds,
|
|
9
|
+
...(opts.createdAt ? { createdAt: opts.createdAt } : {}),
|
|
10
|
+
}));
|
|
11
|
+
}
|
|
12
|
+
export function defaultTargetPath(args) {
|
|
13
|
+
switch (args.target) {
|
|
14
|
+
case "skill-global":
|
|
15
|
+
return join(homedir(), ".keel", "global-skill.md");
|
|
16
|
+
case "skill-local":
|
|
17
|
+
return join(resolve(args.cwd), ".keel", "local-skill.md");
|
|
18
|
+
case "principle-pack":
|
|
19
|
+
return join(resolve(args.cwd), "principles", "index.ts");
|
|
20
|
+
case "architecture":
|
|
21
|
+
return join(resolve(args.cwd), "architecture", "data.ts");
|
|
22
|
+
case "memory":
|
|
23
|
+
return join(resolve(args.cwd), ".keel", "memory.md");
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
//# sourceMappingURL=proposals.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"proposals.js","sourceRoot":"","sources":["../src/proposals.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAClC,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAE1C,OAAO,EACL,4BAA4B,EAC5B,sBAAsB,GAEvB,MAAM,oBAAoB,CAAC;AAU5B,MAAM,UAAU,mCAAmC,CACjD,IAA+B;IAE/B,MAAM,WAAW,GAAuB,4BAA4B,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;IACpF,MAAM,UAAU,GAAG,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;IAC1D,OAAO,WAAW,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAC3B,sBAAsB,CAAC,CAAC,EAAE;QACxB,UAAU;QACV,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,IAAI,CAAC,SAAS,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;KACzD,CAAC,CACH,CAAC;AACJ,CAAC;AAOD,MAAM,UAAU,iBAAiB,CAAC,IAAoB;IACpD,QAAQ,IAAI,CAAC,MAAM,EAAE,CAAC;QACpB,KAAK,cAAc;YACjB,OAAO,IAAI,CAAC,OAAO,EAAE,EAAE,OAAO,EAAE,iBAAiB,CAAC,CAAC;QACrD,KAAK,aAAa;YAChB,OAAO,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,OAAO,EAAE,gBAAgB,CAAC,CAAC;QAC5D,KAAK,gBAAgB;YACnB,OAAO,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,YAAY,EAAE,UAAU,CAAC,CAAC;QAC3D,KAAK,cAAc;YACjB,OAAO,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,cAAc,EAAE,SAAS,CAAC,CAAC;QAC5D,KAAK,QAAQ;YACX,OAAO,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,OAAO,EAAE,WAAW,CAAC,CAAC;IACzD,CAAC;AACH,CAAC"}
|
package/dist/queue.d.ts
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import type { LearningProposal, LearningStatus } from "@keel_flow/schema";
|
|
2
|
+
import type { ParsedSuggestion } from "@keel_flow/reflect";
|
|
3
|
+
import { type GatedProposal } from "./recurrence.js";
|
|
4
|
+
export interface ProposalRecord {
|
|
5
|
+
proposal: LearningProposal;
|
|
6
|
+
suggestion: ParsedSuggestion;
|
|
7
|
+
reflectionPath: string;
|
|
8
|
+
}
|
|
9
|
+
export interface StatusEvent {
|
|
10
|
+
proposalId: string;
|
|
11
|
+
status: LearningStatus;
|
|
12
|
+
ts: string;
|
|
13
|
+
note?: string;
|
|
14
|
+
verifyExitCode?: number;
|
|
15
|
+
}
|
|
16
|
+
export declare function learnLogPath(cwd: string): string;
|
|
17
|
+
export declare function readStatusLog(cwd: string): Promise<StatusEvent[]>;
|
|
18
|
+
export declare function markStatus(proposalId: string, status: LearningStatus, cwd: string, extras?: {
|
|
19
|
+
note?: string;
|
|
20
|
+
verifyExitCode?: number;
|
|
21
|
+
}): Promise<void>;
|
|
22
|
+
export declare function currentStatus(proposalId: string, events: StatusEvent[]): LearningStatus;
|
|
23
|
+
export declare function loadAllProposals(cwd: string): Promise<ProposalRecord[]>;
|
|
24
|
+
export declare function loadPending(opts: {
|
|
25
|
+
cwd: string;
|
|
26
|
+
gate?: boolean;
|
|
27
|
+
}): Promise<ProposalRecord[]>;
|
|
28
|
+
export declare function loadEmerging(opts: {
|
|
29
|
+
cwd: string;
|
|
30
|
+
}): Promise<GatedProposal[]>;
|
|
31
|
+
export declare function loadByStatus(opts: {
|
|
32
|
+
cwd: string;
|
|
33
|
+
status: LearningStatus;
|
|
34
|
+
}): Promise<ProposalRecord[]>;
|
|
35
|
+
//# sourceMappingURL=queue.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"queue.d.ts","sourceRoot":"","sources":["../src/queue.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,gBAAgB,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAE1E,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAC3D,OAAO,EAAoC,KAAK,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAEvF,MAAM,WAAW,cAAc;IAC7B,QAAQ,EAAE,gBAAgB,CAAC;IAC3B,UAAU,EAAE,gBAAgB,CAAC;IAC7B,cAAc,EAAE,MAAM,CAAC;CACxB;AAED,MAAM,WAAW,WAAW;IAC1B,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,cAAc,CAAC;IACvB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAED,wBAAgB,YAAY,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAEhD;AAED,wBAAsB,aAAa,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,EAAE,CAAC,CAcvE;AAED,wBAAsB,UAAU,CAC9B,UAAU,EAAE,MAAM,EAClB,MAAM,EAAE,cAAc,EACtB,GAAG,EAAE,MAAM,EACX,MAAM,GAAE;IAAE,IAAI,CAAC,EAAE,MAAM,CAAC;IAAC,cAAc,CAAC,EAAE,MAAM,CAAA;CAAO,GACtD,OAAO,CAAC,IAAI,CAAC,CAWf;AAED,wBAAgB,aAAa,CAC3B,UAAU,EAAE,MAAM,EAClB,MAAM,EAAE,WAAW,EAAE,GACpB,cAAc,CAIhB;AAED,wBAAsB,gBAAgB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,EAAE,CAAC,CAc7E;AAOD,wBAAsB,WAAW,CAAC,IAAI,EAAE;IACtC,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,CAAC,EAAE,OAAO,CAAC;CAChB,GAAG,OAAO,CAAC,cAAc,EAAE,CAAC,CAM5B;AAED,wBAAsB,YAAY,CAAC,IAAI,EAAE;IAAE,GAAG,EAAE,MAAM,CAAA;CAAE,GAAG,OAAO,CAAC,aAAa,EAAE,CAAC,CAKlF;AAED,wBAAsB,YAAY,CAAC,IAAI,EAAE;IACvC,GAAG,EAAE,MAAM,CAAC;IACZ,MAAM,EAAE,cAAc,CAAC;CACxB,GAAG,OAAO,CAAC,cAAc,EAAE,CAAC,CAM5B"}
|
package/dist/queue.js
ADDED
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import { promises as fs } from "node:fs";
|
|
2
|
+
import { existsSync } from "node:fs";
|
|
3
|
+
import { dirname, join, resolve } from "node:path";
|
|
4
|
+
import { listReflections, parseSuggestionsFromMarkdown, proposalFromSuggestion } from "@keel_flow/reflect";
|
|
5
|
+
import { gateProposals, promotedProposals } from "./recurrence.js";
|
|
6
|
+
export function learnLogPath(cwd) {
|
|
7
|
+
return join(resolve(cwd), ".keel", "learn", "proposals.jsonl");
|
|
8
|
+
}
|
|
9
|
+
export async function readStatusLog(cwd) {
|
|
10
|
+
const path = learnLogPath(cwd);
|
|
11
|
+
if (!existsSync(path))
|
|
12
|
+
return [];
|
|
13
|
+
const raw = await fs.readFile(path, "utf-8");
|
|
14
|
+
const out = [];
|
|
15
|
+
for (const line of raw.split("\n")) {
|
|
16
|
+
if (line.trim().length === 0)
|
|
17
|
+
continue;
|
|
18
|
+
try {
|
|
19
|
+
out.push(JSON.parse(line));
|
|
20
|
+
}
|
|
21
|
+
catch {
|
|
22
|
+
// ignore malformed lines
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
return out;
|
|
26
|
+
}
|
|
27
|
+
export async function markStatus(proposalId, status, cwd, extras = {}) {
|
|
28
|
+
const path = learnLogPath(cwd);
|
|
29
|
+
await fs.mkdir(dirname(path), { recursive: true });
|
|
30
|
+
const entry = {
|
|
31
|
+
proposalId,
|
|
32
|
+
status,
|
|
33
|
+
ts: new Date().toISOString(),
|
|
34
|
+
...(extras.note !== undefined ? { note: extras.note } : {}),
|
|
35
|
+
...(extras.verifyExitCode !== undefined ? { verifyExitCode: extras.verifyExitCode } : {}),
|
|
36
|
+
};
|
|
37
|
+
await fs.appendFile(path, JSON.stringify(entry) + "\n", "utf-8");
|
|
38
|
+
}
|
|
39
|
+
export function currentStatus(proposalId, events) {
|
|
40
|
+
const matches = events.filter((e) => e.proposalId === proposalId);
|
|
41
|
+
if (matches.length === 0)
|
|
42
|
+
return "pending";
|
|
43
|
+
return matches[matches.length - 1].status;
|
|
44
|
+
}
|
|
45
|
+
export async function loadAllProposals(cwd) {
|
|
46
|
+
const reflections = await listReflections(cwd);
|
|
47
|
+
const records = [];
|
|
48
|
+
for (const summary of reflections) {
|
|
49
|
+
const md = await fs.readFile(summary.path, "utf-8");
|
|
50
|
+
const suggestions = parseSuggestionsFromMarkdown(md);
|
|
51
|
+
for (const s of suggestions) {
|
|
52
|
+
const p = proposalFromSuggestion(s, {
|
|
53
|
+
sessionIds: summary.sessionId ? [summary.sessionId] : [],
|
|
54
|
+
});
|
|
55
|
+
records.push({ proposal: p, suggestion: s, reflectionPath: summary.path });
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
return records;
|
|
59
|
+
}
|
|
60
|
+
// Pending proposals that have passed the recurrence/severity gate — this is
|
|
61
|
+
// the human review queue. A lesson reaches it only after recurring across
|
|
62
|
+
// reflections or being flagged critical once (see recurrence.ts). Set
|
|
63
|
+
// `gate: false` to get the ungated pending set (every suggestion), e.g. for
|
|
64
|
+
// diagnostics. `loadEmerging` returns the held-but-not-yet-promoted set.
|
|
65
|
+
export async function loadPending(opts) {
|
|
66
|
+
const events = await readStatusLog(opts.cwd);
|
|
67
|
+
const all = await loadAllProposals(opts.cwd);
|
|
68
|
+
const pending = all.filter((r) => currentStatus(r.proposal.id, events) === "pending");
|
|
69
|
+
if (opts.gate === false)
|
|
70
|
+
return pending;
|
|
71
|
+
return promotedProposals(pending);
|
|
72
|
+
}
|
|
73
|
+
export async function loadEmerging(opts) {
|
|
74
|
+
const events = await readStatusLog(opts.cwd);
|
|
75
|
+
const all = await loadAllProposals(opts.cwd);
|
|
76
|
+
const pending = all.filter((r) => currentStatus(r.proposal.id, events) === "pending");
|
|
77
|
+
return gateProposals(pending).filter((g) => g.state === "emerging");
|
|
78
|
+
}
|
|
79
|
+
export async function loadByStatus(opts) {
|
|
80
|
+
const events = await readStatusLog(opts.cwd);
|
|
81
|
+
const all = await loadAllProposals(opts.cwd);
|
|
82
|
+
return all.filter((r) => currentStatus(r.proposal.id, events) === opts.status);
|
|
83
|
+
}
|
|
84
|
+
//# sourceMappingURL=queue.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"queue.js","sourceRoot":"","sources":["../src/queue.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { ProposalRecord } from "./queue.js";
|
|
2
|
+
export declare const RECURRENCE_THRESHOLD = 2;
|
|
3
|
+
export type PromotionState = "promoted" | "emerging";
|
|
4
|
+
export interface GatedProposal {
|
|
5
|
+
record: ProposalRecord;
|
|
6
|
+
state: PromotionState;
|
|
7
|
+
occurrences: number;
|
|
8
|
+
promotedBy: "recurrence" | "severity" | null;
|
|
9
|
+
reflectionPaths: string[];
|
|
10
|
+
}
|
|
11
|
+
export declare function lessonKey(record: ProposalRecord): string;
|
|
12
|
+
export declare function gateProposals(records: ProposalRecord[]): GatedProposal[];
|
|
13
|
+
export declare function promotedProposals(records: ProposalRecord[]): ProposalRecord[];
|
|
14
|
+
//# sourceMappingURL=recurrence.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"recurrence.d.ts","sourceRoot":"","sources":["../src/recurrence.ts"],"names":[],"mappings":"AAYA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAEjD,eAAO,MAAM,oBAAoB,IAAI,CAAC;AAEtC,MAAM,MAAM,cAAc,GAAG,UAAU,GAAG,UAAU,CAAC;AAErD,MAAM,WAAW,aAAa;IAE5B,MAAM,EAAE,cAAc,CAAC;IACvB,KAAK,EAAE,cAAc,CAAC;IAEtB,WAAW,EAAE,MAAM,CAAC;IAEpB,UAAU,EAAE,YAAY,GAAG,UAAU,GAAG,IAAI,CAAC;IAG7C,eAAe,EAAE,MAAM,EAAE,CAAC;CAC3B;AAMD,wBAAgB,SAAS,CAAC,MAAM,EAAE,cAAc,GAAG,MAAM,CAOxD;AAED,wBAAgB,aAAa,CAAC,OAAO,EAAE,cAAc,EAAE,GAAG,aAAa,EAAE,CA2CxE;AAED,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,cAAc,EAAE,GAAG,cAAc,EAAE,CAI7E"}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
export const RECURRENCE_THRESHOLD = 2;
|
|
2
|
+
// Two suggestions are "the same lesson" when they target the same artifact and
|
|
3
|
+
// have a normalized-equal title. Title normalization is deliberately loose
|
|
4
|
+
// (lowercase, collapse whitespace, strip trailing punctuation) so trivially
|
|
5
|
+
// reworded restatements of the same lesson still group.
|
|
6
|
+
export function lessonKey(record) {
|
|
7
|
+
const title = record.suggestion.title
|
|
8
|
+
.toLowerCase()
|
|
9
|
+
.replace(/\s+/g, " ")
|
|
10
|
+
.replace(/[.!?,;:]+$/g, "")
|
|
11
|
+
.trim();
|
|
12
|
+
return `${record.suggestion.target}::${title}`;
|
|
13
|
+
}
|
|
14
|
+
export function gateProposals(records) {
|
|
15
|
+
const groups = new Map();
|
|
16
|
+
for (const record of records) {
|
|
17
|
+
const key = lessonKey(record);
|
|
18
|
+
const group = groups.get(key);
|
|
19
|
+
if (group)
|
|
20
|
+
group.push(record);
|
|
21
|
+
else
|
|
22
|
+
groups.set(key, [record]);
|
|
23
|
+
}
|
|
24
|
+
const gated = [];
|
|
25
|
+
for (const group of groups.values()) {
|
|
26
|
+
const distinctReflections = new Set(group.map((r) => r.reflectionPath));
|
|
27
|
+
const occurrences = distinctReflections.size;
|
|
28
|
+
const isCritical = group.some((r) => r.suggestion.severity === "high");
|
|
29
|
+
let state = "emerging";
|
|
30
|
+
let promotedBy = null;
|
|
31
|
+
if (isCritical) {
|
|
32
|
+
state = "promoted";
|
|
33
|
+
promotedBy = "severity";
|
|
34
|
+
}
|
|
35
|
+
else if (occurrences >= RECURRENCE_THRESHOLD) {
|
|
36
|
+
state = "promoted";
|
|
37
|
+
promotedBy = "recurrence";
|
|
38
|
+
}
|
|
39
|
+
// Representative = the last occurrence (most recent reflection wins its
|
|
40
|
+
// current wording), but provenance lists every contributing reflection.
|
|
41
|
+
const record = group[group.length - 1];
|
|
42
|
+
gated.push({
|
|
43
|
+
record,
|
|
44
|
+
state,
|
|
45
|
+
occurrences,
|
|
46
|
+
promotedBy,
|
|
47
|
+
reflectionPaths: [...distinctReflections],
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
// Promoted first, then by occurrence count — the review queue surfaces the
|
|
51
|
+
// strongest-evidence lessons at the top.
|
|
52
|
+
return gated.sort((a, b) => {
|
|
53
|
+
if (a.state !== b.state)
|
|
54
|
+
return a.state === "promoted" ? -1 : 1;
|
|
55
|
+
return b.occurrences - a.occurrences;
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
export function promotedProposals(records) {
|
|
59
|
+
return gateProposals(records)
|
|
60
|
+
.filter((g) => g.state === "promoted")
|
|
61
|
+
.map((g) => g.record);
|
|
62
|
+
}
|
|
63
|
+
//# sourceMappingURL=recurrence.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"recurrence.js","sourceRoot":"","sources":["../src/recurrence.ts"],"names":[],"mappings":"AAcA,MAAM,CAAC,MAAM,oBAAoB,GAAG,CAAC,CAAC;AAiBtC,+EAA+E;AAC/E,2EAA2E;AAC3E,4EAA4E;AAC5E,wDAAwD;AACxD,MAAM,UAAU,SAAS,CAAC,MAAsB;IAC9C,MAAM,KAAK,GAAG,MAAM,CAAC,UAAU,CAAC,KAAK;SAClC,WAAW,EAAE;SACb,OAAO,CAAC,MAAM,EAAE,GAAG,CAAC;SACpB,OAAO,CAAC,aAAa,EAAE,EAAE,CAAC;SAC1B,IAAI,EAAE,CAAC;IACV,OAAO,GAAG,MAAM,CAAC,UAAU,CAAC,MAAM,KAAK,KAAK,EAAE,CAAC;AACjD,CAAC;AAED,MAAM,UAAU,aAAa,CAAC,OAAyB;IACrD,MAAM,MAAM,GAAG,IAAI,GAAG,EAA4B,CAAC;IACnD,KAAK,MAAM,MAAM,IAAI,OAAO,EAAE,CAAC;QAC7B,MAAM,GAAG,GAAG,SAAS,CAAC,MAAM,CAAC,CAAC;QAC9B,MAAM,KAAK,GAAG,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QAC9B,IAAI,KAAK;YAAE,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;;YACzB,MAAM,CAAC,GAAG,CAAC,GAAG,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC;IACjC,CAAC;IAED,MAAM,KAAK,GAAoB,EAAE,CAAC;IAClC,KAAK,MAAM,KAAK,IAAI,MAAM,CAAC,MAAM,EAAE,EAAE,CAAC;QACpC,MAAM,mBAAmB,GAAG,IAAI,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,cAAc,CAAC,CAAC,CAAC;QACxE,MAAM,WAAW,GAAG,mBAAmB,CAAC,IAAI,CAAC;QAC7C,MAAM,UAAU,GAAG,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,UAAU,CAAC,QAAQ,KAAK,MAAM,CAAC,CAAC;QAEvE,IAAI,KAAK,GAAmB,UAAU,CAAC;QACvC,IAAI,UAAU,GAAgC,IAAI,CAAC;QACnD,IAAI,UAAU,EAAE,CAAC;YACf,KAAK,GAAG,UAAU,CAAC;YACnB,UAAU,GAAG,UAAU,CAAC;QAC1B,CAAC;aAAM,IAAI,WAAW,IAAI,oBAAoB,EAAE,CAAC;YAC/C,KAAK,GAAG,UAAU,CAAC;YACnB,UAAU,GAAG,YAAY,CAAC;QAC5B,CAAC;QAED,wEAAwE;QACxE,wEAAwE;QACxE,MAAM,MAAM,GAAG,KAAK,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,CAAE,CAAC;QACxC,KAAK,CAAC,IAAI,CAAC;YACT,MAAM;YACN,KAAK;YACL,WAAW;YACX,UAAU;YACV,eAAe,EAAE,CAAC,GAAG,mBAAmB,CAAC;SAC1C,CAAC,CAAC;IACL,CAAC;IAED,2EAA2E;IAC3E,yCAAyC;IACzC,OAAO,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE;QACzB,IAAI,CAAC,CAAC,KAAK,KAAK,CAAC,CAAC,KAAK;YAAE,OAAO,CAAC,CAAC,KAAK,KAAK,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QAChE,OAAO,CAAC,CAAC,WAAW,GAAG,CAAC,CAAC,WAAW,CAAC;IACvC,CAAC,CAAC,CAAC;AACL,CAAC;AAED,MAAM,UAAU,iBAAiB,CAAC,OAAyB;IACzD,OAAO,aAAa,CAAC,OAAO,CAAC;SAC1B,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,KAAK,UAAU,CAAC;SACrC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC;AAC1B,CAAC"}
|
package/package.json
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@keel_flow/learn",
|
|
3
|
+
"version": "0.2.0",
|
|
4
|
+
"private": false,
|
|
5
|
+
"type": "module",
|
|
6
|
+
"publishConfig": {
|
|
7
|
+
"access": "public"
|
|
8
|
+
},
|
|
9
|
+
"files": [
|
|
10
|
+
"dist"
|
|
11
|
+
],
|
|
12
|
+
"main": "./dist/index.js",
|
|
13
|
+
"types": "./dist/index.d.ts",
|
|
14
|
+
"exports": {
|
|
15
|
+
".": {
|
|
16
|
+
"import": "./dist/index.js",
|
|
17
|
+
"require": "./dist/index.js",
|
|
18
|
+
"types": "./dist/index.d.ts"
|
|
19
|
+
}
|
|
20
|
+
},
|
|
21
|
+
"dependencies": {
|
|
22
|
+
"@keel_flow/core": "0.2.0",
|
|
23
|
+
"@keel_flow/reflect": "0.2.0",
|
|
24
|
+
"@keel_flow/runtime": "0.2.0",
|
|
25
|
+
"@keel_flow/schema": "0.2.0",
|
|
26
|
+
"@keel_flow/telemetry": "0.2.0"
|
|
27
|
+
},
|
|
28
|
+
"devDependencies": {
|
|
29
|
+
"@types/node": "^25.9.1",
|
|
30
|
+
"@typescript-eslint/eslint-plugin": "^8.0.0",
|
|
31
|
+
"@typescript-eslint/parser": "^8.0.0",
|
|
32
|
+
"eslint": "^9.0.0",
|
|
33
|
+
"typescript": "^5.5.0",
|
|
34
|
+
"vitest": "^2.0.0"
|
|
35
|
+
},
|
|
36
|
+
"scripts": {
|
|
37
|
+
"build": "tsc",
|
|
38
|
+
"typecheck": "tsc --noEmit",
|
|
39
|
+
"test": "vitest run",
|
|
40
|
+
"lint": "eslint src"
|
|
41
|
+
}
|
|
42
|
+
}
|