loki-mode 10.2.5 → 10.3.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 (71) hide show
  1. package/SKILL.md +2 -2
  2. package/VERSION +1 -1
  3. package/autonomy/lib/engine10-push.sh +12 -1
  4. package/autonomy/lib/modernize/java_capture.sh +444 -0
  5. package/dashboard/__init__.py +1 -1
  6. package/docs/INSTALLATION.md +1 -1
  7. package/docs/v10/BOARD.md +20 -17
  8. package/docs/v10/DECISIONS.md +5 -0
  9. package/docs/v10/GUARDS.md +140 -0
  10. package/docs/v10/PROGRESS.md +5 -0
  11. package/loki-ts/dist/loki.js +532 -517
  12. package/mcp/__init__.py +1 -1
  13. package/package.json +1 -1
  14. package/plugins/loki-mode/.claude-plugin/plugin.json +1 -1
  15. package/web-app/dist/assets/{AdminPage-BOESW7uR.js → AdminPage-CunIYKsu.js} +1 -1
  16. package/web-app/dist/assets/{Avatar-Blm74_mD.js → Avatar-Dpl2qVf5.js} +1 -1
  17. package/web-app/dist/assets/{Badge-DdJmac3t.js → Badge-DDZcQ4uC.js} +1 -1
  18. package/web-app/dist/assets/{Button-Do43CF5O.js → Button-Ccuh5Ouj.js} +1 -1
  19. package/web-app/dist/assets/{CockpitPage-DEPQn2Xm.js → CockpitPage-Dgakdozm.js} +1 -1
  20. package/web-app/dist/assets/{ComparePage-Dp4MSpts.js → ComparePage-9-Zcu9Gf.js} +1 -1
  21. package/web-app/dist/assets/{ErrorBoundary-wTGWFgom.js → ErrorBoundary-CI756a2c.js} +1 -1
  22. package/web-app/dist/assets/{EvidenceReceiptPanel-ChvPQb1U.js → EvidenceReceiptPanel-BC3TA-vV.js} +1 -1
  23. package/web-app/dist/assets/{GitHubIssuesPanel-uB0MpIb7.js → GitHubIssuesPanel-BdCsjPq2.js} +1 -1
  24. package/web-app/dist/assets/{GitHubPRsPanel-B9FSjHfu.js → GitHubPRsPanel-DgXyzC-S.js} +1 -1
  25. package/web-app/dist/assets/{HomePage-CriEbwCE.js → HomePage-Cijve3Mw.js} +2 -2
  26. package/web-app/dist/assets/{LoginPage-DHbNkrh_.js → LoginPage-3exGWWVo.js} +1 -1
  27. package/web-app/dist/assets/{MagicPage-BcpCAml7.js → MagicPage-Bjy-pGNt.js} +1 -1
  28. package/web-app/dist/assets/{MetricsPage-j75KQpua.js → MetricsPage-CpJIaU8q.js} +1 -1
  29. package/web-app/dist/assets/{NotFoundPage-CKbUnP7E.js → NotFoundPage-fpgcK9hA.js} +1 -1
  30. package/web-app/dist/assets/{ProjectPage-BjGf-x2u.js → ProjectPage-O7UQyFey.js} +3 -3
  31. package/web-app/dist/assets/{ProjectsPage-C3kHhUQ7.js → ProjectsPage-DdOZUQGM.js} +1 -1
  32. package/web-app/dist/assets/{SettingsPage-C1yjVDOm.js → SettingsPage-D3lNwNFK.js} +1 -1
  33. package/web-app/dist/assets/{ShowcasePage-DhKkDB_5.js → ShowcasePage-DBeFTDWM.js} +1 -1
  34. package/web-app/dist/assets/{SystemSettingsPage-BfAiCemG.js → SystemSettingsPage-CJhMBNIO.js} +1 -1
  35. package/web-app/dist/assets/{TeamsPage-DGAEPPh1.js → TeamsPage-C6mmPl9W.js} +1 -1
  36. package/web-app/dist/assets/{TemplatesPage-LvQ3hwuA.js → TemplatesPage-Brej2rqO.js} +1 -1
  37. package/web-app/dist/assets/{TerminalOutput-D8jsFsvX.js → TerminalOutput-C__6qBqv.js} +1 -1
  38. package/web-app/dist/assets/{activity-Hime0DJg.js → activity-CrVuKK_W.js} +1 -1
  39. package/web-app/dist/assets/{bell-CGbbuRF4.js → bell-26fqzcLm.js} +1 -1
  40. package/web-app/dist/assets/{bot-CcTLPQ3e.js → bot-DmykFcjH.js} +1 -1
  41. package/web-app/dist/assets/{check-BzO3GwoU.js → check-CzSi5Vci.js} +1 -1
  42. package/web-app/dist/assets/{chevron-left-BRFaXiHd.js → chevron-left-NsdJXeCD.js} +1 -1
  43. package/web-app/dist/assets/{circle-alert-DDl3SqIA.js → circle-alert-BuKEAV8n.js} +1 -1
  44. package/web-app/dist/assets/{clock-CK7f8Yqa.js → clock-DPpOjTHt.js} +1 -1
  45. package/web-app/dist/assets/{cloud-CbMCeoxr.js → cloud-BPy4rC85.js} +1 -1
  46. package/web-app/dist/assets/{code-xml-BpwdRqwP.js → code-xml-CUdET1iT.js} +1 -1
  47. package/web-app/dist/assets/{database-B4JofR5i.js → database-DS_5uXW_.js} +1 -1
  48. package/web-app/dist/assets/{dollar-sign-D3Uo_9Me.js → dollar-sign-CgSGxJa7.js} +1 -1
  49. package/web-app/dist/assets/{file-code-corner-DWrhbnIl.js → file-code-corner-B7iTiGB-.js} +1 -1
  50. package/web-app/dist/assets/{file-plus-Bob-tb45.js → file-plus-rxLXNljV.js} +1 -1
  51. package/web-app/dist/assets/{globe-uJN2j0RG.js → globe-CVJMaRaH.js} +1 -1
  52. package/web-app/dist/assets/{hammer-DHg-1oSy.js → hammer-C9KdE6y9.js} +1 -1
  53. package/web-app/dist/assets/{index-NHr7F-mq.js → index-B21YEJCf.js} +2 -2
  54. package/web-app/dist/assets/{layers-CsbGfI1E.js → layers-DNIDOX7S.js} +1 -1
  55. package/web-app/dist/assets/{loader-circle-C8iaLvST.js → loader-circle-HrXWSqei.js} +1 -1
  56. package/web-app/dist/assets/{lock-B2ZA5xyD.js → lock-SfmCbb4w.js} +1 -1
  57. package/web-app/dist/assets/{package-BIe5yA3N.js → package-CwpZESj_.js} +1 -1
  58. package/web-app/dist/assets/{plus-Dutu3zwz.js → plus-DLh1-x2y.js} +1 -1
  59. package/web-app/dist/assets/{refresh-cw-DAodka-p.js → refresh-cw-DxJsH1dQ.js} +1 -1
  60. package/web-app/dist/assets/{rotate-ccw-BD6KP_Vv.js → rotate-ccw-Dkny920M.js} +1 -1
  61. package/web-app/dist/assets/{scroll-text-YKA_5gyw.js → scroll-text-CsPrAnD5.js} +1 -1
  62. package/web-app/dist/assets/{server-C21dybST.js → server-E6pPKQNp.js} +1 -1
  63. package/web-app/dist/assets/{shield-alert-C70DSrSH.js → shield-alert-C0Xh-M1C.js} +1 -1
  64. package/web-app/dist/assets/{thumbs-up-Cc2gHDZ9.js → thumbs-up-oWNeyoZv.js} +1 -1
  65. package/web-app/dist/assets/{trash-2-Ch7SIljf.js → trash-2-BMv5WQCZ.js} +1 -1
  66. package/web-app/dist/assets/{trending-down-Ssp5wdTa.js → trending-down-CUoz-SBV.js} +1 -1
  67. package/web-app/dist/assets/{trending-up-BnDZm4bU.js → trending-up-CI1-zKRQ.js} +1 -1
  68. package/web-app/dist/assets/{upload-DtQjXwrK.js → upload-CBtBD85L.js} +1 -1
  69. package/web-app/dist/assets/{usePolling-7rvTmkii.js → usePolling-CxtCw8cL.js} +1 -1
  70. package/web-app/dist/assets/{user-4s1moXeZ.js → user-cDtPlp5V.js} +1 -1
  71. package/web-app/dist/index.html +1 -1
package/SKILL.md CHANGED
@@ -3,7 +3,7 @@ name: loki-mode
3
3
  description: Autonomous spec-driven build system with a built-in trust layer. It does not call work done until it is verified (RARV-C closure loop, 8 quality gates, completion council, verified-completion evidence gate). Triggers on "Loki Mode". Takes a spec (PRD, GitHub issue, OpenAPI doc, etc.) to deployed product with minimal human intervention. Provider-agnostic. Requires --dangerously-skip-permissions flag.
4
4
  ---
5
5
 
6
- # Loki Mode v10.2.5
6
+ # Loki Mode v10.3.0
7
7
 
8
8
  **You are an autonomous agent. You make decisions. You do not ask questions. You do not stop.**
9
9
 
@@ -470,4 +470,4 @@ See `CHANGELOG.md` entries [7.5.7], [7.5.8], [7.5.13] for the per-fix list and r
470
470
 
471
471
  ---
472
472
 
473
- **v10.2.5 | [Autonomi](https://www.autonomi.dev/) flagship product | ~410 lines core**
473
+ **v10.3.0 | [Autonomi](https://www.autonomi.dev/) flagship product | ~410 lines core**
package/VERSION CHANGED
@@ -1 +1 @@
1
- 10.2.5
1
+ 10.3.0
@@ -3,6 +3,7 @@
3
3
  #
4
4
  # engine10-push.sh push-pr <repo-dir> <branch> <title> <body-file> [--draft]
5
5
  # engine10-push.sh comment <pr-number> <body-file>
6
+ # engine10-push.sh issue-comment <issue-ref> <body-file>
6
7
  # engine10-push.sh status <sha> <pending|success|failure|error> <description>
7
8
  #
8
9
  # Holds GitHub credentials, runs no LLM, reads no untrusted text. Inputs come
@@ -137,6 +138,16 @@ case "$mode" in
137
138
  [ -z "$_e10_local" ] || { log_info "local origin: no PR to comment on (no-op)"; exit 0; }
138
139
  _e10_gh pr comment "$1" --repo "$_e10_repo" --body-file "$2" || die "gh pr comment failed"
139
140
  ;;
141
+ issue-comment)
142
+ # E-67: a FAILED run with no diff (or no remote) has no PR to open; comment on the issue
143
+ # instead so the run's reason is never silently lost. <issue-ref> is owner/repo#N or #N.
144
+ [ "$#" -eq 2 ] || die "usage: issue-comment <issue-ref> <body-file>"
145
+ num="${1##*#}"
146
+ case "$num" in '' | *[!0-9]*) die "cannot extract issue number from: $1" ;; esac
147
+ [ -f "$2" ] || die "body file not found: $2"
148
+ [ -z "$_e10_local" ] || { log_info "local origin: no issue to comment on (no-op)"; exit 0; }
149
+ _e10_gh issue comment "$num" --repo "$_e10_repo" --body-file "$2" || die "gh issue comment failed"
150
+ ;;
140
151
  status)
141
152
  [ "$#" -eq 3 ] || die "usage: status <sha> <state> <description>"
142
153
  [[ "$1" =~ ^[0-9a-f]{40}$ ]] || die "sha must be 40 lowercase hex characters"
@@ -145,5 +156,5 @@ case "$mode" in
145
156
  _e10_gh api "repos/$_e10_repo/statuses/$1" -f "state=$2" -f context=loki/deep-verify \
146
157
  -f "description=$3" >/dev/null || die "gh api status failed"
147
158
  ;;
148
- *) die "usage: engine10-push.sh push-pr|comment|status ..." ;;
159
+ *) die "usage: engine10-push.sh push-pr|comment|issue-comment|status ..." ;;
149
160
  esac
@@ -0,0 +1,444 @@
1
+ #!/usr/bin/env bash
2
+ # autonomy/lib/modernize/java_capture.sh -- M-11: Java 8 to 21 oracle capture
3
+ # (docs/v10/MODERNIZE.md sections 3.2 and 7: "Run the existing JUnit suite
4
+ # under JDK 8 with the JaCoCo agent. Add Randoop-generated regression tests
5
+ # per unit class ... Cases record the method, serialized arguments ..., the
6
+ # return value, the exception class and stdout.").
7
+ #
8
+ # Split (loki-ts/src/engine10/modernize/oracle/java.ts does every verdict):
9
+ # this script only runs tools and dumps RAW artifacts into --out:
10
+ # status.json -- what was detected: JDK 8 or not, jacoco/randoop jars
11
+ # jacoco.xml -- JaCoCo's own XML report (untouched, so java.ts can
12
+ # parse the real schema instead of a shape this script
13
+ # invents)
14
+ # replay1.jsonl -- one CaptureRunner run's raw case records
15
+ # replay2.jsonl -- a second, independent run of the same cases
16
+ # java.ts applies the double-replay determinism filter, the boundary check,
17
+ # coverage floor and NOT PROVEN reasons -- never this script. This script
18
+ # never claims a case is proven or a coverage number is final.
19
+ #
20
+ # CaptureRunner (embedded below as a heredoc, compiled once per call) does
21
+ # the actual reflection: it walks each unit class's public methods and
22
+ # invokes the capturable ones (primitives, String, List/Set/Map only --
23
+ # ponytail: no attempt to construct arbitrary objects or to replay Randoop's
24
+ # literal call sequences, which would need parsing generated Java source;
25
+ # upgrade path is Randoop's library API (randoop.sequence.Sequence) once a
26
+ # JDK 8 + Randoop jar host exists to build and test it against). A method
27
+ # whose parameter or return type falls outside that set gets ONE case record
28
+ # with a "not_capturable" reason and no invocation -- capture never guesses.
29
+ #
30
+ # Every branch below is exercised in loki-ts/tests/engine10/modernize/
31
+ # java_capture.test.ts with a stubbed PATH (fake java/javac/jacoco/randoop),
32
+ # because this repo has no JDK 8, JaCoCo or Randoop jar to run for real.
33
+ set -uo pipefail
34
+
35
+ usage() {
36
+ echo "usage: java_capture.sh --unit-dir DIR --classes FQCN[,FQCN...] --out DIR" \
37
+ "[--files REL.java[,REL.java...]] [--jacoco-agent JAR] [--jacoco-cli JAR]" \
38
+ "[--randoop-jar JAR] [--test-classpath CP] [--randoop-time-limit SECS]" >&2
39
+ }
40
+
41
+ UNIT_DIR=""
42
+ CLASSES=""
43
+ OUT_DIR=""
44
+ FILES_ARG=""
45
+ JACOCO_AGENT="${LOKI_MOD_JACOCO_AGENT:-}"
46
+ JACOCO_CLI="${LOKI_MOD_JACOCO_CLI:-}"
47
+ RANDOOP_JAR="${LOKI_MOD_RANDOOP_JAR:-}"
48
+ TEST_CLASSPATH=""
49
+ RANDOOP_TIME_LIMIT="20"
50
+
51
+ while [ $# -gt 0 ]; do
52
+ case "$1" in
53
+ --unit-dir) UNIT_DIR="$2"; shift 2 ;;
54
+ --classes) CLASSES="$2"; shift 2 ;;
55
+ --files) FILES_ARG="$2"; shift 2 ;;
56
+ --out) OUT_DIR="$2"; shift 2 ;;
57
+ --jacoco-agent) JACOCO_AGENT="$2"; shift 2 ;;
58
+ --jacoco-cli) JACOCO_CLI="$2"; shift 2 ;;
59
+ --randoop-jar) RANDOOP_JAR="$2"; shift 2 ;;
60
+ --test-classpath) TEST_CLASSPATH="$2"; shift 2 ;;
61
+ --randoop-time-limit) RANDOOP_TIME_LIMIT="$2"; shift 2 ;;
62
+ -h|--help) usage; exit 0 ;;
63
+ *) echo "java_capture.sh: unknown arg: $1" >&2; usage; exit 2 ;;
64
+ esac
65
+ done
66
+
67
+ if [ -z "$UNIT_DIR" ] || [ -z "$CLASSES" ] || [ -z "$OUT_DIR" ]; then
68
+ usage
69
+ exit 2
70
+ fi
71
+
72
+ mkdir -p "$OUT_DIR" || { echo "java_capture.sh: cannot create --out $OUT_DIR" >&2; exit 2; }
73
+
74
+ REASONS=()
75
+ # JSON string escaping: backslash, double quote, then every C0 control character (0x00-0x1F).
76
+ # \n \r \t get their short escapes; the rest (e.g. a stray 0x01 or 0x1B in a user-set
77
+ # LOKI_MOD_JACOCO_AGENT/RANDOOP_JAR path, or an unusual `java -version` line) become \u00XX so
78
+ # status.json is always valid JSON no matter what these values contain. 0x00 is not handled --
79
+ # a bash/env-var string cannot carry a literal NUL byte, so it is unreachable here.
80
+ json_escape() {
81
+ local s="$1"
82
+ s="${s//\\/\\\\}"
83
+ s="${s//\"/\\\"}"
84
+ s="${s//$'\t'/\\t}"
85
+ s="${s//$'\r'/\\r}"
86
+ s="${s//$'\n'/\\n}"
87
+ local i c esc
88
+ for i in {1..31}; do
89
+ case "$i" in 9|10|13) continue ;; esac
90
+ c=$(printf '%b' "\\$(printf '%03o' "$i")")
91
+ esc=$(printf '\\u%04x' "$i")
92
+ s="${s//$c/$esc}"
93
+ done
94
+ printf '%s' "$s"
95
+ }
96
+
97
+ write_status() {
98
+ local jdk8="$1" jdk_raw="$2"
99
+ local reasons_json="[]"
100
+ if [ "${#REASONS[@]}" -gt 0 ]; then
101
+ reasons_json="["
102
+ local first=1
103
+ for r in "${REASONS[@]}"; do
104
+ [ "$first" -eq 1 ] || reasons_json+=","
105
+ reasons_json+="\"$(json_escape "$r")\""
106
+ first=0
107
+ done
108
+ reasons_json+="]"
109
+ fi
110
+ cat > "$OUT_DIR/status.json" <<EOF
111
+ {"jdk8":$jdk8,"jdkVersionRaw":$([ -n "$jdk_raw" ] && echo "\"$(json_escape "$jdk_raw")\"" || echo null),"jacocoAgent":$([ -n "$JACOCO_AGENT" ] && echo "\"$(json_escape "$JACOCO_AGENT")\"" || echo null),"jacocoCli":$([ -n "$JACOCO_CLI" ] && echo "\"$(json_escape "$JACOCO_CLI")\"" || echo null),"randoopJar":$([ -n "$RANDOOP_JAR" ] && echo "\"$(json_escape "$RANDOOP_JAR")\"" || echo null),"reasons":$reasons_json}
112
+ EOF
113
+ }
114
+
115
+ # --- 1. JDK 8 detection --------------------------------------------------
116
+ # A bare `command -v java` succeeds on macOS even with no JDK installed (the
117
+ # /usr/bin/java stub). The only reliable signal is `java -version`'s STDOUT
118
+ # (not stderr -- that varies by vendor/newer JDKs; javac/java both print the
119
+ # version string to stdout as of JDK 10+, and to stderr on 8/9 -- so check
120
+ # both streams rather than assume one).
121
+ if ! command -v java >/dev/null 2>&1; then
122
+ REASONS+=("skipped: no JDK 8" "old runtime unavailable: java not found on PATH")
123
+ write_status false ""
124
+ : > "$OUT_DIR/replay1.jsonl"
125
+ : > "$OUT_DIR/replay2.jsonl"
126
+ : > "$OUT_DIR/jacoco.xml"
127
+ exit 0
128
+ fi
129
+
130
+ JAVA_VER_OUT="$(java -version 2>&1)"
131
+ JDK8=false
132
+ if printf '%s' "$JAVA_VER_OUT" | grep -qE '"(1\.8\.|8\.)'; then
133
+ JDK8=true
134
+ fi
135
+
136
+ if [ "$JDK8" != "true" ]; then
137
+ REASONS+=("skipped: no JDK 8" "old runtime unavailable: detected $(printf '%s' "$JAVA_VER_OUT" | head -1)")
138
+ write_status false "$JAVA_VER_OUT"
139
+ : > "$OUT_DIR/replay1.jsonl"
140
+ : > "$OUT_DIR/replay2.jsonl"
141
+ : > "$OUT_DIR/jacoco.xml"
142
+ exit 0
143
+ fi
144
+
145
+ # --- 2. Compile the unit -------------------------------------------------
146
+ CLASSES_DIR="$OUT_DIR/classes"
147
+ mkdir -p "$CLASSES_DIR"
148
+ # The unit's own file list (--files, repo-relative to --unit-dir) is authoritative when given --
149
+ # oracle/java.ts always passes it, built from the merged M-04 graph, so only the unit's actual
150
+ # files ever get compiled here. Without it (a direct CLI call), every .java under --unit-dir is
151
+ # used, which is only correct when --unit-dir IS the unit (never a shared multi-unit checkout).
152
+ if [ -n "$FILES_ARG" ]; then
153
+ JAVA_FILES=$(printf '%s' "$FILES_ARG" | tr ',' '\n' | sed "s#^#${UNIT_DIR}/#" | tr '\n' ' ')
154
+ else
155
+ JAVA_FILES=$(find "$UNIT_DIR" -name '*.java' 2>/dev/null)
156
+ fi
157
+ if [ -z "$JAVA_FILES" ]; then
158
+ REASONS+=("no .java files found under --unit-dir")
159
+ write_status true "$JAVA_VER_OUT"
160
+ : > "$OUT_DIR/replay1.jsonl"
161
+ : > "$OUT_DIR/replay2.jsonl"
162
+ : > "$OUT_DIR/jacoco.xml"
163
+ exit 0
164
+ fi
165
+ # shellcheck disable=SC2086
166
+ if ! javac -d "$CLASSES_DIR" -cp "$TEST_CLASSPATH" $JAVA_FILES > "$OUT_DIR/javac.log" 2>&1; then
167
+ REASONS+=("javac failed: see javac.log")
168
+ write_status true "$JAVA_VER_OUT"
169
+ : > "$OUT_DIR/replay1.jsonl"
170
+ : > "$OUT_DIR/replay2.jsonl"
171
+ : > "$OUT_DIR/jacoco.xml"
172
+ exit 0
173
+ fi
174
+
175
+ # --- 3. Existing JUnit suite under the JaCoCo agent (coverage only) -----
176
+ # ponytail: not run. java_capture.sh only receives the unit's production FQCNs (--classes) --
177
+ # never which of them are JUnit test classes, because M-04/M-05 do not yet tag test files
178
+ # separately from production files in the unit graph. Running JUnitCore against the production
179
+ # classes (the previous behaviour here) executed no actual tests and silently mislabeled
180
+ # coverage as measuring the existing suite, so it is removed rather than kept wrong. Upgrade
181
+ # path: once the unit graph distinguishes test files, thread their FQCNs through as their own
182
+ # flag and run JUnitCore on those (not $CLASSES), under this same agent, before CaptureRunner.
183
+ EXEC_FILE="$OUT_DIR/jacoco.exec"
184
+ REASONS+=("existing JUnit suite not run: no test classes given to java_capture.sh")
185
+ if [ -z "$JACOCO_AGENT" ] || [ ! -f "$JACOCO_AGENT" ]; then
186
+ REASONS+=("jacoco agent not available: coverage not measured")
187
+ fi
188
+
189
+ # --- 4. Randoop regression tests: generated, compiled, smoke-run --------
190
+ # Randoop's own generated tests are run to confirm they compile and pass, but NOT under the
191
+ # jacoco agent: their branches are not yet turned into oracle cases (see the CaptureRunner
192
+ # comment below), so counting their coverage into EXEC_FILE would let branch_pct clear the 80%
193
+ # floor on branches cases.jsonl does not actually cover -- the exact failure this slice's review
194
+ # reproduced. ponytail: parsing Randoop's generated call sequences into cases.jsonl via the
195
+ # double replay (section 7) is not implemented; upgrade path is Randoop's library API
196
+ # (randoop.sequence.Sequence) once a JDK 8 + Randoop jar host exists to build against.
197
+ if [ -n "$RANDOOP_JAR" ] && [ -f "$RANDOOP_JAR" ]; then
198
+ RANDOOP_OUT="$OUT_DIR/randoop-tests"
199
+ mkdir -p "$RANDOOP_OUT"
200
+ RANDOOP_TESTCLASS_ARGS=()
201
+ IFS=',' read -ra RANDOOP_CLASS_LIST <<< "$CLASSES"
202
+ for rc in "${RANDOOP_CLASS_LIST[@]}"; do
203
+ RANDOOP_TESTCLASS_ARGS+=("--testclass=$rc")
204
+ done
205
+ (cd "$RANDOOP_OUT" && java -cp "${RANDOOP_JAR}:${CLASSES_DIR}" randoop.main.Main gentests \
206
+ "${RANDOOP_TESTCLASS_ARGS[@]}" \
207
+ --time-limit="$RANDOOP_TIME_LIMIT" \
208
+ --junit-output-dir="$RANDOOP_OUT" \
209
+ --regression-test-basename=RandoopRegression \
210
+ > "$OUT_DIR/randoop.log" 2>&1) || REASONS+=("randoop exited non-zero: see randoop.log")
211
+ RANDOOP_JAVA=$(find "$RANDOOP_OUT" -name '*.java' 2>/dev/null)
212
+ if [ -n "$RANDOOP_JAVA" ]; then
213
+ # shellcheck disable=SC2086
214
+ if javac -d "$CLASSES_DIR" -cp "${RANDOOP_JAR}:${CLASSES_DIR}" $RANDOOP_JAVA \
215
+ > "$OUT_DIR/randoop-javac.log" 2>&1; then
216
+ RANDOOP_CLASSES=$(cd "$RANDOOP_OUT" && find . -name '*.java' | sed 's#^\./##; s#\.java$##; s#/#.#g' | tr '\n' ' ')
217
+ # shellcheck disable=SC2086
218
+ java -cp "${CLASSES_DIR}:${RANDOOP_JAR}" org.junit.runner.JUnitCore \
219
+ $RANDOOP_CLASSES > "$OUT_DIR/junit-randoop.log" 2>&1 || true
220
+ REASONS+=("randoop tests generated and run but not yet added as oracle cases: double-replay of generated sequences not implemented")
221
+ else
222
+ REASONS+=("randoop-generated tests failed to compile: see randoop-javac.log")
223
+ fi
224
+ else
225
+ REASONS+=("randoop produced no regression tests")
226
+ fi
227
+ else
228
+ REASONS+=("randoop jar not available: no generated regression tests")
229
+ fi
230
+
231
+ # --- 5. CaptureRunner: reflective double replay (coverage source) -------
232
+ RUNNER_SRC="$OUT_DIR/CaptureRunner.java"
233
+ cat > "$RUNNER_SRC" <<'JAVA_EOF'
234
+ import java.lang.reflect.*;
235
+ import java.io.*;
236
+ import java.util.*;
237
+
238
+ /** M-11 embedded capture runner: for each given class, invokes every public
239
+ * capturable method (primitives/wrappers, String, List/Set/Map params and
240
+ * return only) with one canned argument per parameter, and writes one JSON
241
+ * case record per method to the given output file. A method outside that
242
+ * type set gets a not_capturable record with no invocation -- never guessed. */
243
+ public final class CaptureRunner {
244
+ static final Set<Class<?>> SCALAR = new HashSet<Class<?>>(Arrays.asList(
245
+ boolean.class, Boolean.class, byte.class, Byte.class, short.class, Short.class,
246
+ int.class, Integer.class, long.class, Long.class, float.class, Float.class,
247
+ double.class, Double.class, char.class, Character.class, String.class));
248
+
249
+ static boolean capturable(Class<?> t) {
250
+ if (t == void.class || t == Void.class) return true;
251
+ if (SCALAR.contains(t)) return true;
252
+ return List.class.isAssignableFrom(t) || Set.class.isAssignableFrom(t) || Map.class.isAssignableFrom(t);
253
+ }
254
+
255
+ static Object canned(Class<?> t) {
256
+ if (t == boolean.class || t == Boolean.class) return Boolean.TRUE;
257
+ if (t == byte.class || t == Byte.class) return (byte) 1;
258
+ if (t == short.class || t == Short.class) return (short) 1;
259
+ if (t == int.class || t == Integer.class) return 1;
260
+ if (t == long.class || t == Long.class) return 1L;
261
+ if (t == float.class || t == Float.class) return 1.0f;
262
+ if (t == double.class || t == Double.class) return 1.0d;
263
+ if (t == char.class || t == Character.class) return 'a';
264
+ if (t == String.class) return "a";
265
+ if (List.class.isAssignableFrom(t)) return new ArrayList<Object>();
266
+ if (Set.class.isAssignableFrom(t)) return new TreeSet<Object>();
267
+ if (Map.class.isAssignableFrom(t)) return new TreeMap<Object, Object>();
268
+ return null;
269
+ }
270
+
271
+ static String esc(String s) {
272
+ StringBuilder b = new StringBuilder();
273
+ for (int i = 0; i < s.length(); i++) {
274
+ char c = s.charAt(i);
275
+ if (c == '"' || c == '\\') b.append('\\').append(c);
276
+ else if (c == '\n') b.append("\\n");
277
+ else if (c == '\r') b.append("\\r");
278
+ else if (c == '\t') b.append("\\t");
279
+ else if (c < 0x20) b.append(String.format("\\u%04x", (int) c));
280
+ else b.append(c);
281
+ }
282
+ return b.toString();
283
+ }
284
+
285
+ static String tag(Object v) {
286
+ if (v == null) return "{\"t\":\"none\"}";
287
+ if (v instanceof Boolean) return "{\"t\":\"bool\",\"v\":" + v + "}";
288
+ if (v instanceof Byte || v instanceof Short || v instanceof Integer || v instanceof Long) {
289
+ return "{\"t\":\"int\",\"v\":\"" + v + "\"}";
290
+ }
291
+ if (v instanceof Float || v instanceof Double) {
292
+ double d = ((Number) v).doubleValue();
293
+ String s = Double.isNaN(d) ? "\"nan\"" : Double.isInfinite(d) ? (d > 0 ? "\"inf\"" : "\"-inf\"") : String.valueOf(d);
294
+ return "{\"t\":\"float\",\"v\":" + s + "}";
295
+ }
296
+ if (v instanceof Character) return "{\"t\":\"text\",\"v\":\"" + esc(String.valueOf(v)) + "\"}";
297
+ if (v instanceof String) return "{\"t\":\"text\",\"v\":\"" + esc((String) v) + "\"}";
298
+ if (v instanceof List || v instanceof Set) {
299
+ StringBuilder b = new StringBuilder("{\"t\":\"list\",\"v\":[");
300
+ boolean first = true;
301
+ for (Object o : (Iterable<?>) v) {
302
+ if (!first) b.append(",");
303
+ b.append(tag(o));
304
+ first = false;
305
+ }
306
+ return b.append("]}").toString();
307
+ }
308
+ if (v instanceof Map) {
309
+ StringBuilder b = new StringBuilder("{\"t\":\"dict\",\"v\":[");
310
+ boolean first = true;
311
+ for (Map.Entry<?, ?> e : ((Map<?, ?>) v).entrySet()) {
312
+ if (!first) b.append(",");
313
+ b.append("[").append(tag(e.getKey())).append(",").append(tag(e.getValue())).append("]");
314
+ first = false;
315
+ }
316
+ return b.append("]}").toString();
317
+ }
318
+ return "{\"t\":\"unsupported\",\"type\":\"" + esc(v.getClass().getName()) + "\"}";
319
+ }
320
+
321
+ public static void main(String[] args) throws Exception {
322
+ if (args.length < 2) {
323
+ System.err.println("usage: CaptureRunner <out.jsonl> <FQCN>[,FQCN...]");
324
+ System.exit(2);
325
+ }
326
+ PrintWriter out = new PrintWriter(new FileWriter(args[0]));
327
+ for (String fqcn : args[1].split(",")) {
328
+ Class<?> cls;
329
+ try {
330
+ cls = Class.forName(fqcn);
331
+ } catch (Throwable t) {
332
+ out.println("{\"class\":\"" + esc(fqcn) + "\",\"method\":null,\"not_capturable\":[\"boundary:class " + esc(fqcn) + " failed to load\"]}");
333
+ continue;
334
+ }
335
+ Object instance = null;
336
+ boolean hasCtor = false;
337
+ try {
338
+ Constructor<?> c = cls.getDeclaredConstructor();
339
+ hasCtor = Modifier.isPublic(c.getModifiers());
340
+ } catch (Throwable ignored) {
341
+ hasCtor = false;
342
+ }
343
+ for (Method m : cls.getDeclaredMethods()) {
344
+ if (!Modifier.isPublic(m.getModifiers()) || m.isSynthetic() || m.isBridge()) continue;
345
+ Class<?>[] ptypes = m.getParameterTypes();
346
+ // Signature includes each parameter's simple type name, not just the count --
347
+ // same-name overloads with equal arity (add(int,int) vs add(String,String))
348
+ // would otherwise collide into one downstream map key and silently drop a case.
349
+ StringBuilder sigParams = new StringBuilder();
350
+ for (int i = 0; i < ptypes.length; i++) {
351
+ if (i > 0) sigParams.append(",");
352
+ sigParams.append(ptypes[i].getSimpleName());
353
+ }
354
+ String sig = fqcn + "#" + m.getName() + "(" + sigParams + ")";
355
+ boolean okParams = true;
356
+ for (Class<?> p : ptypes) if (!capturable(p)) okParams = false;
357
+ boolean okReturn = capturable(m.getReturnType());
358
+ boolean staticOk = Modifier.isStatic(m.getModifiers()) || hasCtor;
359
+ if (!okParams || !okReturn || !staticOk) {
360
+ String reason = !staticOk ? "no public zero-arg constructor" : "parameter or return type not capturable";
361
+ out.println("{\"class\":\"" + esc(fqcn) + "\",\"method\":\"" + esc(sig) + "\",\"not_capturable\":[\"boundary:" + esc(reason) + "\"]}");
362
+ continue;
363
+ }
364
+ Object[] callArgs = new Object[ptypes.length];
365
+ for (int i = 0; i < ptypes.length; i++) callArgs[i] = canned(ptypes[i]);
366
+ if (instance == null && !Modifier.isStatic(m.getModifiers())) {
367
+ try {
368
+ Constructor<?> c = cls.getDeclaredConstructor();
369
+ c.setAccessible(true);
370
+ instance = c.newInstance();
371
+ } catch (Throwable t) {
372
+ out.println("{\"class\":\"" + esc(fqcn) + "\",\"method\":\"" + esc(sig) + "\",\"not_capturable\":[\"boundary:constructor threw\"]}");
373
+ continue;
374
+ }
375
+ }
376
+ ByteArrayOutputStream buf = new ByteArrayOutputStream();
377
+ PrintStream prevOut = System.out;
378
+ Object ret = null;
379
+ Throwable exc = null;
380
+ try {
381
+ System.setOut(new PrintStream(buf, true, "UTF-8"));
382
+ m.setAccessible(true);
383
+ ret = m.invoke(Modifier.isStatic(m.getModifiers()) ? null : instance, callArgs);
384
+ } catch (InvocationTargetException e) {
385
+ exc = e.getCause() != null ? e.getCause() : e;
386
+ } catch (Throwable t) {
387
+ exc = t;
388
+ } finally {
389
+ System.setOut(prevOut);
390
+ }
391
+ StringBuilder argsJson = new StringBuilder("[");
392
+ for (int i = 0; i < callArgs.length; i++) {
393
+ if (i > 0) argsJson.append(",");
394
+ argsJson.append(tag(callArgs[i]));
395
+ }
396
+ argsJson.append("]");
397
+ String stdout = buf.toString("UTF-8");
398
+ String excJson = exc == null ? "null" : "{\"type\":\"" + esc(exc.getClass().getName()) + "\"}";
399
+ String retJson = exc == null ? tag(ret) : "null";
400
+ out.println("{\"class\":\"" + esc(fqcn) + "\",\"method\":\"" + esc(sig) + "\",\"args\":" + argsJson
401
+ + ",\"return\":" + retJson + ",\"exc\":" + excJson + ",\"stdout\":\"" + esc(stdout) + "\",\"not_capturable\":[]}");
402
+ }
403
+ }
404
+ out.close();
405
+ }
406
+ }
407
+ JAVA_EOF
408
+
409
+ if javac -d "$OUT_DIR" "$RUNNER_SRC" > "$OUT_DIR/runner-javac.log" 2>&1; then
410
+ # Only replay1 carries the jacoco agent: branch_pct must measure exactly the run that
411
+ # produced cases.jsonl, never a second, redundant pass -- replay2 exists purely for the
412
+ # determinism check above, not for coverage.
413
+ if [ -n "$JACOCO_AGENT" ] && [ -f "$JACOCO_AGENT" ]; then
414
+ java "-javaagent:${JACOCO_AGENT}=destfile=${EXEC_FILE},append=true" \
415
+ -cp "${OUT_DIR}:${CLASSES_DIR}" CaptureRunner "$OUT_DIR/replay1.jsonl" "$CLASSES" \
416
+ > "$OUT_DIR/replay1.log" 2>&1 || REASONS+=("CaptureRunner replay 1 exited non-zero")
417
+ else
418
+ java -cp "${OUT_DIR}:${CLASSES_DIR}" CaptureRunner "$OUT_DIR/replay1.jsonl" "$CLASSES" \
419
+ > "$OUT_DIR/replay1.log" 2>&1 || REASONS+=("CaptureRunner replay 1 exited non-zero")
420
+ fi
421
+ java -cp "${OUT_DIR}:${CLASSES_DIR}" CaptureRunner "$OUT_DIR/replay2.jsonl" "$CLASSES" \
422
+ > "$OUT_DIR/replay2.log" 2>&1 || REASONS+=("CaptureRunner replay 2 exited non-zero")
423
+ else
424
+ REASONS+=("CaptureRunner failed to compile: see runner-javac.log")
425
+ : > "$OUT_DIR/replay1.jsonl"
426
+ : > "$OUT_DIR/replay2.jsonl"
427
+ fi
428
+
429
+ # --- 6. JaCoCo XML report (raw, untouched -- java.ts parses it) ---------
430
+ # Runs after CaptureRunner so EXEC_FILE (written above, replay1 only) is complete before the
431
+ # report is built from it -- generating the report before the coverage-producing run even
432
+ # happened (the previous ordering here) always reported empty or stale coverage.
433
+ if [ -n "$JACOCO_CLI" ] && [ -f "$JACOCO_CLI" ] && [ -f "$EXEC_FILE" ]; then
434
+ java -jar "$JACOCO_CLI" report "$EXEC_FILE" \
435
+ --classfiles "$CLASSES_DIR" --sourcefiles "$UNIT_DIR" \
436
+ --xml "$OUT_DIR/jacoco.xml" > "$OUT_DIR/jacoco-report.log" 2>&1 \
437
+ || REASONS+=("jacococli report failed: see jacoco-report.log")
438
+ else
439
+ REASONS+=("jacoco report not generated: agent, cli or exec data missing")
440
+ : > "$OUT_DIR/jacoco.xml"
441
+ fi
442
+
443
+ write_status true "$JAVA_VER_OUT"
444
+ exit 0
@@ -7,7 +7,7 @@ Modules:
7
7
  control: Session control API (start/stop/pause/resume)
8
8
  """
9
9
 
10
- __version__ = "10.2.5"
10
+ __version__ = "10.3.0"
11
11
 
12
12
  # Expose the control app for easy import
13
13
  try:
@@ -2,7 +2,7 @@
2
2
 
3
3
  The flagship product of [Autonomi](https://www.autonomi.dev/). Loki Mode is a spec-driven autonomous builder with a built-in trust layer that takes any spec to a deployed product and verifies completion with evidence (quality gates plus a completion council), not just a "done" claim. Complete installation instructions for all platforms and use cases.
4
4
 
5
- **Version:** v10.2.5
5
+ **Version:** v10.3.0
6
6
 
7
7
  ---
8
8