@open-tomato/rafa 0.18.0 → 0.19.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.
@@ -11,6 +11,7 @@ import {
11
11
  REQUIRED_ITEM_KEYS,
12
12
  SKILL_TIERS,
13
13
  STORE_BACKENDS,
14
+ confidence,
14
15
  dayCount,
15
16
  describeValue,
16
17
  flag,
@@ -24,6 +25,7 @@ import {
24
25
  moduleSource,
25
26
  oneOf,
26
27
  optionalPrerequisite,
28
+ recurrenceCount,
27
29
  releaseEnabled,
28
30
  requiredPrerequisite,
29
31
  routeTarget,
@@ -32,7 +34,7 @@ import {
32
34
  tierPin,
33
35
  tierSwitch,
34
36
  usdAmount
35
- } from "./index-944pncd8.js";
37
+ } from "./index-cedghpva.js";
36
38
 
37
39
  // src/config-schema.ts
38
40
  import { join } from "path";
@@ -238,6 +240,9 @@ var CONFIG_DEFAULTS = Object.freeze({
238
240
  trackerDefault: "github",
239
241
  trackerFallback: Object.freeze(["local"]),
240
242
  learningAdapter: "local",
243
+ learningBlessMinConfidence: 0.5,
244
+ learningPromoteAfter: 3,
245
+ learningPromoteMinConfidence: 0.7,
241
246
  outputMode: "text",
242
247
  prerequisitesRequired: Object.freeze([]),
243
248
  prerequisitesOptional: Object.freeze([]),
@@ -288,6 +293,9 @@ var SETTINGS = {
288
293
  read: text("a learning adapter name"),
289
294
  cli: true
290
295
  },
296
+ learningBlessMinConfidence: { key: "learning.bless.minConfidence", read: confidence, cli: false },
297
+ learningPromoteAfter: { key: "learning.promote.after", read: recurrenceCount, cli: false },
298
+ learningPromoteMinConfidence: { key: "learning.promote.minConfidence", read: confidence, cli: false },
291
299
  outputMode: { key: "output.mode", read: oneOf(OUTPUT_MODES), cli: true },
292
300
  prerequisitesRequired: {
293
301
  key: "prerequisites.required",
@@ -442,6 +450,9 @@ function readLayer(rawOf, atOf) {
442
450
  trackerDefault: read("trackerDefault"),
443
451
  trackerFallback: read("trackerFallback"),
444
452
  learningAdapter: read("learningAdapter"),
453
+ learningBlessMinConfidence: read("learningBlessMinConfidence"),
454
+ learningPromoteAfter: read("learningPromoteAfter"),
455
+ learningPromoteMinConfidence: read("learningPromoteMinConfidence"),
445
456
  outputMode: read("outputMode"),
446
457
  prerequisitesRequired: read("prerequisitesRequired"),
447
458
  prerequisitesOptional: read("prerequisitesOptional"),
@@ -685,6 +696,239 @@ function readRafaBlocks(markdown) {
685
696
  return blocks;
686
697
  }
687
698
 
699
+ // src/report/parse.ts
700
+ var REPORT_STATUSES = ["done", "blocked"];
701
+ var FINDING_KINDS = ["gotcha", "pattern", "location", "skill-suggestion"];
702
+ var FINDING_SIGNALS = ["loud", "silent"];
703
+ var FINDING_DOMAINS = [
704
+ "code-style",
705
+ "testing",
706
+ "git",
707
+ "debugging",
708
+ "workflow",
709
+ "security",
710
+ "general-best-practices"
711
+ ];
712
+ var CHANGE_LEVELS = ["patch", "minor", "major", "none"];
713
+ var REPORT_KIND = "report";
714
+ var REQUIRED = true;
715
+ var OPTIONAL = false;
716
+ var REPORT_KEYS = [
717
+ "status",
718
+ "feedback",
719
+ "findings",
720
+ "skills_used",
721
+ "blockers",
722
+ "out_of_scope_bugs",
723
+ "changes"
724
+ ];
725
+ var FINDING_KEYS = [
726
+ "trigger",
727
+ "kind",
728
+ "what",
729
+ "cause",
730
+ "resolution",
731
+ "artifact",
732
+ "signal",
733
+ "domain"
734
+ ];
735
+ var BLOCKER_KEYS = ["what", "artifact"];
736
+ var BUG_KEYS = ["what", "artifact", "security"];
737
+ var CHANGE_KEYS = ["level", "area", "summary"];
738
+ function isMapping2(value) {
739
+ return typeof value === "object" && value !== null && !Array.isArray(value);
740
+ }
741
+ function isOneOf(choices, value) {
742
+ return choices.includes(value);
743
+ }
744
+ function describeValue2(value) {
745
+ if (typeof value === "string")
746
+ return JSON.stringify(value);
747
+ if (value === null)
748
+ return "nothing";
749
+ if (Array.isArray(value))
750
+ return "a list";
751
+ if (typeof value === "object")
752
+ return "a mapping";
753
+ return `the ${typeof value} ${String(value)}`;
754
+ }
755
+ function messageOf2(error) {
756
+ return error instanceof Error ? error.message : String(error);
757
+ }
758
+ function reportIssue(reason, field, text2) {
759
+ return { reason, field, text: text2 };
760
+ }
761
+ function absent(reason, block, text2) {
762
+ return { present: false, reason, block, text: text2 };
763
+ }
764
+ function scopeOf(mapping, keys, prefix, issues) {
765
+ const fields = new Map;
766
+ const extras = [];
767
+ for (const [key, value] of Object.entries(mapping)) {
768
+ if (keys.includes(key))
769
+ fields.set(key, value);
770
+ else
771
+ extras.push({ key, value });
772
+ }
773
+ return { fields, extras, prefix, issues };
774
+ }
775
+ function valueOf(scope, key, required) {
776
+ const value = scope.fields.get(key) ?? null;
777
+ if (value === null && required) {
778
+ const field = `${scope.prefix}${key}`;
779
+ scope.issues.push(reportIssue("missing-field", field, `${field} is missing`));
780
+ }
781
+ return value;
782
+ }
783
+ function unusable(scope, key, why) {
784
+ const field = `${scope.prefix}${key}`;
785
+ scope.issues.push(reportIssue("unusable-field", field, `${field} ${why}`));
786
+ return null;
787
+ }
788
+ function stringProblem(value) {
789
+ if (typeof value !== "string")
790
+ return `is ${describeValue2(value)}, not a string; quote it`;
791
+ if (value.trim().length === 0)
792
+ return "is blank";
793
+ return null;
794
+ }
795
+ function stringField(scope, key, required) {
796
+ const value = valueOf(scope, key, required);
797
+ if (value === null)
798
+ return null;
799
+ const problem = stringProblem(value);
800
+ return problem === null ? value : unusable(scope, key, problem);
801
+ }
802
+ function choiceField(scope, key, choices, required) {
803
+ const value = valueOf(scope, key, required);
804
+ if (value === null || isOneOf(choices, value))
805
+ return value;
806
+ return unusable(scope, key, `is ${describeValue2(value)}, not one of ${choices.join(", ")}`);
807
+ }
808
+ function booleanField(scope, key, required) {
809
+ const value = valueOf(scope, key, required);
810
+ if (value === null || typeof value === "boolean")
811
+ return value;
812
+ return unusable(scope, key, `is ${describeValue2(value)}, not true or false; write it unquoted`);
813
+ }
814
+ function listField(scope, key, readEntry) {
815
+ const value = valueOf(scope, key, OPTIONAL);
816
+ if (value === null)
817
+ return [];
818
+ if (!Array.isArray(value)) {
819
+ unusable(scope, key, `is ${describeValue2(value)}, not a list`);
820
+ return [];
821
+ }
822
+ const entries = [];
823
+ const items = value;
824
+ for (const [index, item] of items.entries()) {
825
+ const entry = readEntry(item, `${scope.prefix}${key}[${index}]`, scope.issues);
826
+ if (entry !== null)
827
+ entries.push(entry);
828
+ }
829
+ return entries;
830
+ }
831
+ function entryScope(item, field, keys, issues) {
832
+ if (isMapping2(item))
833
+ return scopeOf(item, keys, `${field}.`, issues);
834
+ const text2 = `${field} is ${describeValue2(item)}, not a mapping of ${keys.join(", ")}; dropped`;
835
+ issues.push(reportIssue("unusable-field", field, text2));
836
+ return null;
837
+ }
838
+ function readSkill(item, field, issues) {
839
+ const problem = stringProblem(item);
840
+ if (problem === null)
841
+ return item;
842
+ issues.push(reportIssue("unusable-field", field, `${field} ${problem}; dropped`));
843
+ return null;
844
+ }
845
+ function readFinding(item, field, issues) {
846
+ const scope = entryScope(item, field, FINDING_KEYS, issues);
847
+ if (scope === null)
848
+ return null;
849
+ return {
850
+ trigger: stringField(scope, "trigger", REQUIRED),
851
+ kind: choiceField(scope, "kind", FINDING_KINDS, REQUIRED),
852
+ what: stringField(scope, "what", REQUIRED),
853
+ cause: stringField(scope, "cause", OPTIONAL),
854
+ resolution: stringField(scope, "resolution", OPTIONAL),
855
+ artifact: stringField(scope, "artifact", OPTIONAL),
856
+ signal: choiceField(scope, "signal", FINDING_SIGNALS, REQUIRED),
857
+ domain: choiceField(scope, "domain", FINDING_DOMAINS, OPTIONAL),
858
+ extras: scope.extras
859
+ };
860
+ }
861
+ function readBlocker(item, field, issues) {
862
+ const scope = entryScope(item, field, BLOCKER_KEYS, issues);
863
+ if (scope === null)
864
+ return null;
865
+ return {
866
+ what: stringField(scope, "what", REQUIRED),
867
+ artifact: stringField(scope, "artifact", OPTIONAL),
868
+ extras: scope.extras
869
+ };
870
+ }
871
+ function readBug(item, field, issues) {
872
+ const scope = entryScope(item, field, BUG_KEYS, issues);
873
+ if (scope === null)
874
+ return null;
875
+ return {
876
+ what: stringField(scope, "what", REQUIRED),
877
+ artifact: stringField(scope, "artifact", OPTIONAL),
878
+ security: booleanField(scope, "security", REQUIRED),
879
+ extras: scope.extras
880
+ };
881
+ }
882
+ function readChange(item, field, issues) {
883
+ const scope = entryScope(item, field, CHANGE_KEYS, issues);
884
+ if (scope === null)
885
+ return null;
886
+ return {
887
+ level: choiceField(scope, "level", CHANGE_LEVELS, REQUIRED),
888
+ area: stringField(scope, "area", OPTIONAL),
889
+ summary: stringField(scope, "summary", REQUIRED),
890
+ extras: scope.extras
891
+ };
892
+ }
893
+ function readReport(document, issues) {
894
+ const scope = scopeOf(document, REPORT_KEYS, "", issues);
895
+ return {
896
+ status: choiceField(scope, "status", REPORT_STATUSES, REQUIRED),
897
+ feedback: stringField(scope, "feedback", OPTIONAL),
898
+ findings: listField(scope, "findings", readFinding),
899
+ skillsUsed: listField(scope, "skills_used", readSkill),
900
+ blockers: listField(scope, "blockers", readBlocker),
901
+ outOfScopeBugs: listField(scope, "out_of_scope_bugs", readBug),
902
+ changes: listField(scope, "changes", readChange),
903
+ extras: scope.extras
904
+ };
905
+ }
906
+ function parseReport(output) {
907
+ const reports = readRafaBlocks(output).filter((block2) => block2.kind === REPORT_KIND);
908
+ const block = reports.at(-1);
909
+ if (block === undefined) {
910
+ return absent("no-block", null, "the session output holds no rafa:report block");
911
+ }
912
+ const line = block.span.first;
913
+ if (!block.closed) {
914
+ return absent("unclosed-block", block, `rafa:report block at line ${line} is never closed, so its body may have been cut short ` + "and is not read");
915
+ }
916
+ let document;
917
+ try {
918
+ document = Bun.YAML.parse(block.body);
919
+ } catch (error) {
920
+ const text2 = `rafa:report block at line ${line} is not valid YAML (${messageOf2(error)})`;
921
+ return absent("malformed-block", block, text2);
922
+ }
923
+ if (!isMapping2(document)) {
924
+ const text2 = `rafa:report block at line ${line} holds ${describeValue2(document)}, ` + "not a mapping of report fields";
925
+ return absent("malformed-block", block, text2);
926
+ }
927
+ const issues = [];
928
+ const report = readReport(document, issues);
929
+ return { present: true, report, block, issues };
930
+ }
931
+
688
932
  // src/adapters/output/text.ts
689
933
  var DEBUG_VERBOSITY = 2;
690
934
  function formatPayload(payload) {
@@ -773,4 +1017,4 @@ function activeOutputMode() {
773
1017
  return activeMode;
774
1018
  }
775
1019
 
776
- export { pinKey, pinLine, collisionMessage, readItemBytes, resolveTiers, findTierItem, DEFAULT_ROUTES, DEFAULT_ROUTING, CONFIG_FILE, CONFIG_DEFAULTS, SETTINGS, ConfigError, configFilePath, parseConfigText, resolveConfig, createTextOutput, activeOutput, activeOutputMode, RAFA_BLOCK_KINDS, isRafaBlockKind, readRafaBlocks };
1020
+ export { pinKey, pinLine, collisionMessage, readItemBytes, resolveTiers, findTierItem, DEFAULT_ROUTES, DEFAULT_ROUTING, CONFIG_FILE, CONFIG_DEFAULTS, SETTINGS, ConfigError, configFilePath, parseConfigText, resolveConfig, RAFA_BLOCK_KINDS, isRafaBlockKind, readRafaBlocks, REPORT_STATUSES, FINDING_KINDS, FINDING_SIGNALS, FINDING_DOMAINS, CHANGE_LEVELS, parseReport, createTextOutput, activeOutput, activeOutputMode };
@@ -1,7 +1,7 @@
1
1
  // @bun
2
2
  import {
3
3
  describeValue
4
- } from "./index-944pncd8.js";
4
+ } from "./index-cedghpva.js";
5
5
 
6
6
  // src/cli/spends.ts
7
7
  var SPENDS_GLYPH = "\uD83E\uDE99";
@@ -0,0 +1,18 @@
1
+ // @bun
2
+ var __require = import.meta.require;
3
+
4
+ // src/learning/identity.ts
5
+ import { createHash } from "crypto";
6
+ var GAP = 0.1;
7
+ var SOURCE_STEP = 0.05;
8
+ var CONFIDENCE_MIN = 0.3;
9
+ var CONFIDENCE_MAX = 0.9;
10
+ var WHITESPACE_RUN = /\s+/g;
11
+ function actionHash(action) {
12
+ return createHash("sha256").update(action.trim().toLowerCase()).digest("hex");
13
+ }
14
+ function triggerKey(trigger) {
15
+ return trigger.trim().toLowerCase().replace(WHITESPACE_RUN, " ");
16
+ }
17
+
18
+ export { __require, GAP, SOURCE_STEP, CONFIDENCE_MIN, CONFIDENCE_MAX, actionHash, triggerKey };
package/dist/index.js CHANGED
@@ -20,25 +20,21 @@ import {
20
20
  start,
21
21
  usage,
22
22
  validateManifest
23
- } from "./index-6vkd153j.js";
23
+ } from "./index-ca0fccvr.js";
24
24
  import {
25
- FINDING_KINDS,
26
- FINDING_SIGNALS,
27
25
  PLAN_BLOCK_KINDS,
28
26
  PLAN_HEADER_FIELDS,
29
27
  PROBE_TIMEOUT_MS,
30
- REPORT_STATUSES,
31
28
  loadPlanPrerequisites,
32
29
  mergePlanPrerequisites,
33
30
  parsePlan,
34
31
  parsePrerequisites,
35
- parseReport,
36
32
  planPrerequisites,
37
33
  prerequisitesPathForPlan,
38
34
  renderInjection,
39
35
  runPreflight,
40
36
  runShellProbe
41
- } from "./index-0pdsq2hy.js";
37
+ } from "./index-09p41s0n.js";
42
38
  import {
43
39
  CORE_ADAPTER_REGISTRY,
44
40
  EFFORT_KEY_PROJECTIONS,
@@ -47,20 +43,25 @@ import {
47
43
  openNdjsonStore,
48
44
  openSqliteStore,
49
45
  selectEffortStore
50
- } from "./index-at9f1z2z.js";
46
+ } from "./index-gb51x34c.js";
51
47
  import {
52
48
  CONFIG_DEFAULTS,
53
49
  CONFIG_FILE,
54
50
  ConfigError,
51
+ FINDING_KINDS,
52
+ FINDING_SIGNALS,
55
53
  RAFA_BLOCK_KINDS,
54
+ REPORT_STATUSES,
56
55
  configFilePath,
57
56
  isRafaBlockKind,
58
57
  parseConfigText,
58
+ parseReport,
59
59
  readRafaBlocks,
60
60
  resolveConfig
61
- } from "./index-jva32qe6.js";
62
- import"./index-kvnggvyk.js";
63
- import"./index-ddf85qac.js";
61
+ } from "./index-pqrpcfaz.js";
62
+ import"./index-d6d0942q.js";
63
+ import"./index-c5cecsga.js";
64
+ import"./index-vg7ycs94.js";
64
65
  import {
65
66
  CLAUDE_SETTING_SOURCES,
66
67
  CONFIG_VERSIONS,
@@ -71,7 +72,8 @@ import {
71
72
  PR_PROVIDERS,
72
73
  RELEASE_AUTO,
73
74
  STORE_BACKENDS
74
- } from "./index-944pncd8.js";
75
+ } from "./index-cedghpva.js";
76
+ import"./index-wp8c28fd.js";
75
77
  export {
76
78
  validateManifest,
77
79
  usage as usageCommand,
@@ -0,0 +1,25 @@
1
+ // @bun
2
+ import {
3
+ bless,
4
+ merge,
5
+ promotable
6
+ } from "../index-d6d0942q.js";
7
+ import {
8
+ CONFIDENCE_MAX,
9
+ CONFIDENCE_MIN,
10
+ GAP,
11
+ SOURCE_STEP,
12
+ actionHash,
13
+ triggerKey
14
+ } from "../index-wp8c28fd.js";
15
+ export {
16
+ triggerKey,
17
+ promotable,
18
+ merge,
19
+ bless,
20
+ actionHash,
21
+ SOURCE_STEP,
22
+ GAP,
23
+ CONFIDENCE_MIN,
24
+ CONFIDENCE_MAX
25
+ };
@@ -1,30 +1,31 @@
1
1
  // @bun
2
2
  import {
3
- FINDING_KINDS,
4
- FINDING_SIGNALS,
5
3
  PLAN_BLOCK_KINDS,
6
4
  PLAN_HEADER_FIELDS,
7
5
  PROBE_TIMEOUT_MS,
8
- REPORT_STATUSES,
9
6
  loadPlanPrerequisites,
10
7
  mergePlanPrerequisites,
11
8
  parsePlan,
12
9
  parsePrerequisites,
13
- parseReport,
14
10
  planPrerequisites,
15
11
  prerequisitesPathForPlan,
16
12
  renderInjection,
17
13
  runPreflight,
18
14
  runShellProbe
19
- } from "../index-0pdsq2hy.js";
15
+ } from "../index-09p41s0n.js";
20
16
  import {
17
+ FINDING_KINDS,
18
+ FINDING_SIGNALS,
21
19
  RAFA_BLOCK_KINDS,
20
+ REPORT_STATUSES,
22
21
  isRafaBlockKind,
22
+ parseReport,
23
23
  readRafaBlocks
24
- } from "../index-jva32qe6.js";
24
+ } from "../index-pqrpcfaz.js";
25
25
  import {
26
26
  INJECT_MODES
27
- } from "../index-944pncd8.js";
27
+ } from "../index-cedghpva.js";
28
+ import"../index-wp8c28fd.js";
28
29
  export {
29
30
  runShellProbe,
30
31
  runPreflight,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@open-tomato/rafa",
3
- "version": "0.18.0",
3
+ "version": "0.19.0",
4
4
  "description": "Alpha. Runs a plan through the ralph loop: one Claude Code session per task, one commit per task, then a pull request and a CI wait.",
5
5
  "private": false,
6
6
  "publishConfig": {
@@ -37,7 +37,8 @@
37
37
  "./cli": "./dist/cli.js",
38
38
  "./plan": "./dist/plan/index.js",
39
39
  "./store": "./dist/effort/store/index.js",
40
- "./ports": "./dist/ports/index.js"
40
+ "./ports": "./dist/ports/index.js",
41
+ "./learning": "./dist/learning/index.js"
41
42
  },
42
43
  "files": [
43
44
  "dist",
@@ -47,7 +48,7 @@
47
48
  "bun": ">=1.3.14"
48
49
  },
49
50
  "scripts": {
50
- "build": "rm -rf dist && bun build src/rafa.ts --target=bun --outfile=dist/cli.js && bun build src/index.ts src/plan/index.ts src/effort/store/index.ts src/ports/index.ts --target=bun --splitting --root=src --outdir=dist && cp src/PROMPT.md src/plan-prompt.md dist/ && cp -R src/bundled dist/bundled && bun build src/tools/ts-symbols/cli.ts --target=bun --outfile=dist/bundled/bin/ts-symbols && for tree in pr/plans:plans board/templates:templates; do src=src/${tree%:*}; out=dist/${tree#*:}; [ -d \"$src\" ] || continue; mkdir -p \"$out\" && cp \"$src\"/*.md \"$out\"/ || exit 1; done",
51
+ "build": "rm -rf dist && bun build src/rafa.ts --target=bun --outfile=dist/cli.js && bun build src/index.ts src/plan/index.ts src/effort/store/index.ts src/ports/index.ts src/learning/index.ts --target=bun --splitting --root=src --outdir=dist && cp src/PROMPT.md src/plan-prompt.md dist/ && cp -R src/bundled dist/bundled && bun build src/tools/ts-symbols/cli.ts --target=bun --outfile=dist/bundled/bin/ts-symbols && for tree in pr/plans:plans board/templates:templates; do src=src/${tree%:*}; out=dist/${tree#*:}; [ -d \"$src\" ] || continue; mkdir -p \"$out\" && cp \"$src\"/*.md \"$out\"/ || exit 1; done",
51
52
  "prepack": "bun run build",
52
53
  "test": "bun test",
53
54
  "lint": "eslint .",