okstra 0.170.3 → 0.172.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/docs/architecture.md +13 -0
  2. package/docs/cli.md +4 -2
  3. package/docs/for-ai/skills/okstra-user-response.md +2 -2
  4. package/docs/project-structure-overview.md +3 -1
  5. package/package.json +1 -1
  6. package/runtime/BUILD.json +2 -2
  7. package/runtime/prompts/launch.template.md +4 -0
  8. package/runtime/prompts/lead/adapters/cmux.md +1 -1
  9. package/runtime/prompts/lead/okstra-lead-contract.md +36 -12
  10. package/runtime/prompts/lead/plan-body-verification.md +22 -11
  11. package/runtime/prompts/lead/report-writer.md +11 -10
  12. package/runtime/prompts/lead/team-contract.md +2 -0
  13. package/runtime/prompts/profiles/_clarification-recommendation.md +3 -1
  14. package/runtime/prompts/profiles/_common-contract.md +2 -1
  15. package/runtime/prompts/profiles/implementation-planning.md +8 -1
  16. package/runtime/python/okstra_ctl/adapters/hosts/antigravity/relay.md +1 -1
  17. package/runtime/python/okstra_ctl/adapters/hosts/claude-code/relay.md +1 -1
  18. package/runtime/python/okstra_ctl/adapters/hosts/codex/relay.md +1 -1
  19. package/runtime/python/okstra_ctl/adapters/hosts/external/relay.md +1 -1
  20. package/runtime/python/okstra_ctl/adapters/hosts/grok/relay.md +1 -1
  21. package/runtime/python/okstra_ctl/adapters/hosts/kimi/relay.md +1 -1
  22. package/runtime/python/okstra_ctl/agent_activity.py +306 -0
  23. package/runtime/python/okstra_ctl/clarification_items.py +37 -20
  24. package/runtime/python/okstra_ctl/cmux.py +144 -59
  25. package/runtime/python/okstra_ctl/lead_events.py +47 -4
  26. package/runtime/python/okstra_ctl/render.py +11 -3
  27. package/runtime/python/okstra_ctl/report_finalize.py +51 -14
  28. package/runtime/python/okstra_ctl/report_html/common.py +5 -3
  29. package/runtime/python/okstra_ctl/report_html/view_models/implementation_planning.py +17 -1
  30. package/runtime/python/okstra_ctl/report_translation.py +14 -0
  31. package/runtime/python/okstra_ctl/worker_audit_ledger.py +150 -0
  32. package/runtime/schemas/final-report-v2.0.schema.json +189 -0
  33. package/runtime/skills/okstra-user-response/SKILL.md +2 -2
  34. package/runtime/templates/reports/final-report-v2.template.md +8 -0
  35. package/runtime/templates/reports/html/assets/base.css +7 -0
  36. package/runtime/templates/reports/html/i18n/en.json +6 -1
  37. package/runtime/templates/reports/html/i18n/ko.json +6 -1
  38. package/runtime/templates/reports/html/macros/forms.html +21 -2
  39. package/runtime/templates/reports/html/tasks/implementation-planning.template.html +25 -0
  40. package/runtime/templates/reports/i18n/en.json +4 -0
  41. package/runtime/templates/reports/report.js +26 -17
  42. package/runtime/templates/reports/user-response.template.md +3 -1
  43. package/runtime/templates/worker-prompt-preamble.md +8 -0
  44. package/runtime/validators/validate-run.py +989 -29
  45. package/runtime/validators/validate_session_conformance.py +523 -35
  46. package/src/cli-registry.mjs +7 -0
  47. package/src/commands/report/agent-activity.mjs +21 -0
@@ -44,33 +44,37 @@
44
44
  return String(s == null ? "" : s).replace(/^\s+|\s+$/g, "");
45
45
  }
46
46
 
47
- // Read the user-supplied value out of one clarification row. Returns
48
- // the empty string when the row has no usable widget, the widget is
49
- // disabled, the select sits on its blank "(선택)" placeholder, or the
50
- // "기타" branch has an empty input. Caller decides whether to emit
51
- // an entry.
52
- function readRowValue(row) {
47
+ // Read the user-supplied value and decision effect from one clarification
48
+ // row. Returns null when the row has no usable input.
49
+ function readRowInput(row) {
53
50
  var sel = row.querySelector("select[data-response-id]");
54
51
  if (sel) {
55
- if (sel.disabled) return "";
52
+ if (sel.disabled) return null;
56
53
  var picked = sel.value;
57
- if (picked === "") return "";
54
+ if (picked === "") return null;
58
55
  if (picked === "__other__") {
59
56
  var rid = sel.getAttribute("data-response-id") || "";
60
57
  var other = row.querySelector('textarea[data-other-for="' + rid + '"]');
61
- return other ? trimMultiline(other.value) : "";
58
+ if (other) {
59
+ var otherValue = trimMultiline(other.value);
60
+ return otherValue ? { value: otherValue, disposition: "answer" } : null;
61
+ }
62
62
  }
63
63
  var opt = sel.options[sel.selectedIndex];
64
64
  // Use the visible option text ("(a) one-time backfill") so the
65
65
  // user-response sidecar stays human-readable, not just "a".
66
- return opt ? trimMultiline(opt.textContent) : picked;
66
+ return {
67
+ value: opt ? trimMultiline(opt.textContent) : picked,
68
+ disposition: opt ? (opt.getAttribute("data-disposition") || "answer") : "answer",
69
+ };
67
70
  }
68
71
  var ta = row.querySelector("textarea[data-response-id]");
69
72
  if (ta) {
70
- if (ta.disabled) return "";
71
- return trimMultiline(ta.value);
73
+ if (ta.disabled) return null;
74
+ var value = trimMultiline(ta.value);
75
+ return value ? { value: value, disposition: "answer" } : null;
72
76
  }
73
- return "";
77
+ return null;
74
78
  }
75
79
 
76
80
  function collectEntries() {
@@ -84,13 +88,14 @@
84
88
  );
85
89
  for (var i = 0; i < rows.length; i++) {
86
90
  var row = rows[i];
87
- var value = readRowValue(row);
88
- if (!value) continue;
91
+ var input = readRowInput(row);
92
+ if (!input) continue;
89
93
  entries.push({
90
94
  responseId: row.getAttribute("data-response-id") || "",
91
95
  kind: row.getAttribute("data-kind") || "",
92
- value: value,
96
+ value: input.value,
93
97
  rationale: null,
98
+ disposition: input.disposition,
94
99
  });
95
100
  }
96
101
  return entries;
@@ -460,11 +465,15 @@
460
465
  // globalThis (works under ESM where the parent uses `vm.runInThisContext`
461
466
  // — see tests/test_report_views.py for the byte-identity harness).
462
467
  if (typeof module !== "undefined" && module.exports) {
463
- module.exports = { buildUserResponseMarkdown: buildUserResponseMarkdown };
468
+ module.exports = {
469
+ buildUserResponseMarkdown: buildUserResponseMarkdown,
470
+ collectEntries: collectEntries,
471
+ };
464
472
  }
465
473
  if (typeof globalThis !== "undefined") {
466
474
  globalThis.__okstraReportViewExports__ = {
467
475
  buildUserResponseMarkdown: buildUserResponseMarkdown,
476
+ collectEntries: collectEntries,
468
477
  };
469
478
  }
470
479
  })();
@@ -25,12 +25,14 @@ The schema of each response block:
25
25
  ```markdown
26
26
  ## <Response ID>
27
27
  - Kind: <material | decision | data-point>
28
- - Disposition: <answer | reframe> # omit the line when answer (default). reframe = defer the answer + re-ask (row stays unresolved)
28
+ - Disposition: <answer | reframe | select | accept-risk | request-revision | reject> # omit the line when answer (default)
29
29
  - Value:
30
30
  > <multi-line value, trimmed>
31
31
  - Rationale: <optional one-line rationale>
32
32
  ```
33
33
 
34
+ `answer`, `select`, `accept-risk`, `request-revision`, and `reject` count as user answers when `Value` is non-empty. `reframe` alone does not count as an answer; it defers the answer and asks the next run to present the row again.
35
+
34
36
  An empty response set (when the user presses Export without filling in any row) outputs the following single line in the body:
35
37
 
36
38
  ```markdown
@@ -21,6 +21,14 @@ When `**Evidence ledger:** required-v1` is present, append one canonical row to
21
21
 
22
22
  Every file citation in the result MUST use backticks, a line suffix, and the same project-relative path its ledger row carries — for example `src/config/env.ts:1-22`. A bare filename (`env.ts:1-22`) does not match its row and fails exactly like a file you never opened, however many times you cited the full path earlier. A cited path without a matching ledger row fails Phase 7 in `validators/validate-run.py` `validate_worker_results_audit()`. Do not add a row for a file you did not open.
23
23
 
24
+ ## Evidence command ledger
25
+
26
+ Append one canonical JSON row to the audit sidecar for each command that produced or verified a conclusion:
27
+
28
+ - Evidence command: {"command":"npm run check","cwd":"<project-root>","exitCode":0,"outputSummary":"all checks passed"}
29
+
30
+ Do not record commands used only to explore, including `rg`, `ls`, and file-opening commands. Do not record environment variable values, tokens, credentials, or authorization headers. `okstra worker-audit-check` rejects malformed command rows and rows containing potential sensitive material through `okstra_ctl.worker_audit_ledger`.
31
+
24
32
  ## Anchor headers (lead-injected, BLOCKING)
25
33
 
26
34
  Every initial analysis prompt begins with these generated anchors in this exact order, before any other content: