@azure-id/orc 1.9.2 → 2.1.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 (228) hide show
  1. package/CHANGELOG.md +722 -0
  2. package/README-id.md +56 -42
  3. package/README.md +58 -41
  4. package/bin/build-agents.js +125 -29
  5. package/bin/clear-logs.js +620 -0
  6. package/bin/cli.js +1873 -180
  7. package/bin/fix.js +459 -0
  8. package/bin/gotcha-import.js +1081 -0
  9. package/bin/gotcha.js +1566 -0
  10. package/bin/graph-query.js +1 -1
  11. package/bin/graph.js +717 -717
  12. package/bin/habit.js +1538 -0
  13. package/bin/mockrun-catalog.js +284 -276
  14. package/bin/onboarding-content.js +2 -1
  15. package/bin/pricing.json +28 -21
  16. package/bin/run-undo.js +398 -0
  17. package/bin/trace-write.js +869 -0
  18. package/bin/verify-contracts.js +627 -100
  19. package/bin/verify-package.js +68 -10
  20. package/bin/webui/api.js +151 -6
  21. package/bin/webui/app.html +239 -232
  22. package/bin/webui/css/00-tokens.css +110 -92
  23. package/bin/webui/css/04-motion.css +87 -0
  24. package/bin/webui/css/06-responsive.css +203 -178
  25. package/bin/webui/css/panels/behaviour.css +205 -0
  26. package/bin/webui/css/panels/hookui.css +79 -0
  27. package/bin/webui/fixtures/behaviour.js +562 -0
  28. package/bin/webui/fixtures/extra.js +9 -9
  29. package/bin/webui/fixtures/flow.js +81 -81
  30. package/bin/webui/fixtures/hookui.js +506 -431
  31. package/bin/webui/fixtures/index.js +66 -3
  32. package/bin/webui/fixtures/knowledge.js +9 -3
  33. package/bin/webui/fixtures/maintenance.js +123 -42
  34. package/bin/webui/fixtures/rules.js +1007 -1002
  35. package/bin/webui/fixtures/settings.js +6 -7
  36. package/bin/webui/fixtures/stats.js +25 -6
  37. package/bin/webui/fixtures/wait.js +98 -97
  38. package/bin/webui/i18n/en/behaviour.json +156 -0
  39. package/bin/webui/i18n/en/hookui.json +290 -194
  40. package/bin/webui/i18n/en/maintenance.json +71 -52
  41. package/bin/webui/i18n/en/nav.json +25 -24
  42. package/bin/webui/i18n/en/settings.json +60 -60
  43. package/bin/webui/i18n/en/tour.json +37 -35
  44. package/bin/webui/i18n/id/behaviour.json +156 -0
  45. package/bin/webui/i18n/id/hookui.json +290 -194
  46. package/bin/webui/i18n/id/maintenance.json +71 -52
  47. package/bin/webui/i18n/id/nav.json +25 -24
  48. package/bin/webui/i18n/id/settings.json +60 -60
  49. package/bin/webui/i18n/id/tour.json +37 -35
  50. package/bin/webui/js/01-i18n.js +155 -154
  51. package/bin/webui/js/05-banners.js +181 -172
  52. package/bin/webui/js/06-edit.js +193 -183
  53. package/bin/webui/js/90-tour.js +498 -494
  54. package/bin/webui/js/91-shortcuts.js +126 -126
  55. package/bin/webui/js/99-boot.js +121 -118
  56. package/bin/webui/js/panels/behaviour.js +1087 -0
  57. package/bin/webui/js/panels/hookui.js +2196 -1691
  58. package/bin/webui/js/panels/maintenance.js +336 -235
  59. package/bin/webui/js/panels/settings.js +726 -719
  60. package/mock-run/INDEX.md +110 -107
  61. package/mock-run/extra-slots.md +1 -1
  62. package/mock-run/gotcha-import.md +118 -0
  63. package/mock-run/habits.md +129 -0
  64. package/mock-run/orc-aftermath.md +392 -392
  65. package/mock-run/orc-budget.md +29 -33
  66. package/mock-run/orc-cli.md +200 -200
  67. package/mock-run/orc-explain.md +86 -86
  68. package/mock-run/orc-extra.md +389 -392
  69. package/mock-run/orc-fix.md +87 -0
  70. package/mock-run/orc-pattern.md +112 -112
  71. package/mock-run/orc-quick.md +6 -1
  72. package/mock-run/orc.md +157 -157
  73. package/package.json +1 -1
  74. package/templates/agents/MODEL-MAPPING.md +37 -34
  75. package/templates/agents/orc-advisor-opus-5-xhigh.md +1 -7
  76. package/templates/agents/orc-analyze-mini-opus-5-med.md +1 -6
  77. package/templates/agents/orc-analyze-mini-sonnet-5-high.md +2 -5
  78. package/templates/agents/{orc-claude-writer-opus-4-8-high.md → orc-claude-writer-opus-5-low.md} +48 -53
  79. package/templates/agents/orc-context-combiner-opus-5-high.md +1 -11
  80. package/templates/agents/orc-executor-haiku-4-5.md +14 -6
  81. package/templates/agents/orc-executor-opus-4-7-high.md +14 -6
  82. package/templates/agents/orc-executor-opus-4-7-med.md +14 -6
  83. package/templates/agents/orc-executor-opus-4-8-high.md +14 -6
  84. package/templates/agents/orc-executor-opus-5-high.md +14 -6
  85. package/templates/agents/orc-executor-opus-5-low.md +14 -6
  86. package/templates/agents/orc-executor-opus-5-med.md +14 -6
  87. package/templates/agents/orc-executor-sonnet-4-6-high.md +14 -6
  88. package/templates/agents/orc-executor-sonnet-4-6-med.md +14 -6
  89. package/templates/agents/orc-executor-sonnet-5-high.md +15 -7
  90. package/templates/agents/orc-executor-sonnet-5-low.md +155 -0
  91. package/templates/agents/orc-executor-sonnet-5-med.md +155 -0
  92. package/templates/agents/orc-graph-noter-sonnet-4-6-med.md +1 -10
  93. package/templates/agents/orc-judge-opus-5-xhigh.md +5 -9
  94. package/templates/agents/orc-learn-writer-opus-5-low.md +1 -7
  95. package/templates/agents/orc-pattern-codifier-opus-5-med.md +1 -8
  96. package/templates/agents/orc-pattern-codifier-sonnet-5-high.md +58 -63
  97. package/templates/agents/orc-planner-mini-opus-5-med.md +1 -4
  98. package/templates/agents/orc-planner-mini-sonnet-5-high.md +2 -3
  99. package/templates/agents/orc-planner-opus-5-med.md +1 -4
  100. package/templates/agents/orc-recon-opus-5-low.md +1 -8
  101. package/templates/agents/orc-recon-sonnet-4-6-med.md +1 -8
  102. package/templates/agents/orc-retro-opus-5-med.md +6 -8
  103. package/templates/agents/orc-retro-sonnet-5-high.md +7 -8
  104. package/templates/agents/orc-reviewer-opus-5-low.md +96 -0
  105. package/templates/agents/orc-scout-opus-5-low.md +1 -6
  106. package/templates/agents/orc-scout-sonnet-4-6-high.md +35 -39
  107. package/templates/agents/orc-system-analyst-opus-5-high.md +1 -6
  108. package/templates/agents/orc-test-author-opus-5-med.md +4 -5
  109. package/templates/agents/orc-trace-writer-haiku-4-5.md +3 -7
  110. package/templates/agents/orc-verifier-opus-5-med.md +16 -8
  111. package/templates/agents/{orc-wiki-scanner-opus-4-8-high.md → orc-wiki-scanner-opus-5-low.md} +74 -79
  112. package/templates/agents/orc-wiki-scanner-sonnet-5-high.md +97 -106
  113. package/templates/commands/orc-analyze.md +13 -21
  114. package/templates/commands/orc-fast.md +10 -15
  115. package/templates/commands/orc-fix.md +18 -0
  116. package/templates/commands/orc-poly.md +12 -21
  117. package/templates/commands/orc-pr-driver.md +11 -30
  118. package/templates/commands/orc-pr-setup.md +10 -31
  119. package/templates/commands/orc-route.md +11 -41
  120. package/templates/commands/orc-test.md +5 -60
  121. package/templates/commands/orc-wiki.md +64 -64
  122. package/templates/hooks/README.md +109 -7
  123. package/templates/hooks/orc-session-hook.js +339 -0
  124. package/templates/hooks/orc-statusline-render.js +317 -23
  125. package/templates/hooks/orc-statusline.js +165 -50
  126. package/templates/hooks/orc-subagent-line.js +23 -5
  127. package/templates/hooks/orc-weather-fetch.js +123 -0
  128. package/templates/skills/_shared/README.md +9 -0
  129. package/templates/skills/_shared/code-graph.md +47 -55
  130. package/templates/skills/_shared/config-precedence.md +3 -1
  131. package/templates/skills/_shared/extra-dispatch.md +78 -93
  132. package/templates/skills/_shared/gotchas.md +248 -177
  133. package/templates/skills/_shared/habits.md +101 -0
  134. package/templates/skills/_shared/lane-contract.md +84 -0
  135. package/templates/skills/_shared/opus5-only.md +14 -14
  136. package/templates/skills/_shared/phases/README.md +142 -83
  137. package/templates/skills/_shared/phases/analyst-gates.md +10 -21
  138. package/templates/skills/_shared/phases/execution.md +8 -14
  139. package/templates/skills/_shared/phases/house-rules.md +27 -32
  140. package/templates/skills/_shared/phases/intake.md +127 -133
  141. package/templates/skills/_shared/phases/mock-example.md +46 -56
  142. package/templates/skills/_shared/phases/plan-handoff.md +91 -97
  143. package/templates/skills/_shared/phases/planning.md +7 -17
  144. package/templates/skills/_shared/phases/preflight.md +19 -42
  145. package/templates/skills/_shared/phases/review.md +24 -28
  146. package/templates/skills/_shared/phases/rules.md +18 -42
  147. package/templates/skills/_shared/phases/scoring.md +55 -65
  148. package/templates/skills/_shared/phases/security-checklist.md +46 -50
  149. package/templates/skills/_shared/phases/security.md +45 -55
  150. package/templates/skills/_shared/phases/ship.md +6 -15
  151. package/templates/skills/_shared/phases/stop-resume.md +2 -5
  152. package/templates/skills/_shared/phases/summary.md +73 -48
  153. package/templates/skills/_shared/phases/testgen.md +41 -51
  154. package/templates/skills/_shared/phases/trace-verbs.md +447 -0
  155. package/templates/skills/_shared/phases/trace.md +66 -297
  156. package/templates/skills/_shared/phases/verify.md +62 -70
  157. package/templates/skills/_shared/phases/wave-grouping.md +128 -133
  158. package/templates/skills/_shared/phases/wiki-consult.md +10 -6
  159. package/templates/skills/_shared/read-ladder.md +2 -55
  160. package/templates/skills/_shared/return-validation.md +17 -70
  161. package/templates/skills/_shared/review-slice.md +106 -0
  162. package/templates/skills/_shared/smoke-gate.md +46 -28
  163. package/templates/skills/_shared/wait.md +1 -0
  164. package/templates/skills/context-combiner/SKILL.md +15 -44
  165. package/templates/skills/orc/README.md +2 -2
  166. package/templates/skills/orc/SKILL.md +35 -63
  167. package/templates/skills/orc/config.md +25 -27
  168. package/templates/skills/orc/examples/full-run-mock.md +2 -1
  169. package/templates/skills/orc/references/effort-and-mode.md +17 -17
  170. package/templates/skills/orc/references/pattern-gate.md +89 -89
  171. package/templates/skills/orc/references/phases/intake.md +41 -47
  172. package/templates/skills/orc/references/phases/integration.md +13 -19
  173. package/templates/skills/orc/references/preflight-report.md +11 -12
  174. package/templates/skills/orc/references/ultra-mode.md +9 -7
  175. package/templates/skills/orc/schemas/checkpoint.md +122 -122
  176. package/templates/skills/orc/subskills/orc-execution/SKILL.md +27 -73
  177. package/templates/skills/orc/subskills/orc-execution/core.md +12 -99
  178. package/templates/skills/orc/subskills/orc-execution/subagent.md +14 -13
  179. package/templates/skills/orc/subskills/orc-review-verify/SKILL.md +12 -53
  180. package/templates/skills/orc/subskills/orc-review-verify/core.md +52 -135
  181. package/templates/skills/orc/subskills/orc-review-verify/subagent.md +7 -7
  182. package/templates/skills/orc/subskills/orc-testgen/SKILL.md +11 -22
  183. package/templates/skills/orc/subskills/orc-testgen/core.md +20 -59
  184. package/templates/skills/orc/subskills/orc-testgen/subagent.md +7 -7
  185. package/templates/skills/orc-advisor/SKILL.md +56 -60
  186. package/templates/skills/orc-analyze/SKILL.md +33 -67
  187. package/templates/skills/orc-analyze/schemas/report-audit.md +2 -1
  188. package/templates/skills/orc-analyze/schemas/report-prose.md +2 -1
  189. package/templates/skills/orc-analyze-mini/SKILL.md +35 -70
  190. package/templates/skills/orc-claude/SKILL.md +14 -14
  191. package/templates/skills/orc-claude/examples/claude-run-mock.md +65 -65
  192. package/templates/skills/orc-diy/README.md +31 -0
  193. package/templates/skills/orc-diy/SKILL.md +27 -78
  194. package/templates/skills/orc-diy/references/blocks/pattern.md +18 -18
  195. package/templates/skills/orc-fast/SKILL.md +49 -75
  196. package/templates/skills/orc-fix/SKILL.md +110 -0
  197. package/templates/skills/orc-judge/SKILL.md +77 -82
  198. package/templates/skills/orc-mini/SKILL.md +64 -112
  199. package/templates/skills/orc-mini/examples/mini-run-mock.md +4 -2
  200. package/templates/skills/orc-pattern/SKILL.md +27 -48
  201. package/templates/skills/orc-poly/SKILL.md +32 -61
  202. package/templates/skills/orc-pr-driver/SKILL.md +25 -51
  203. package/templates/skills/orc-pr-driver/references/green-gate.md +113 -105
  204. package/templates/skills/orc-pr-setup/SKILL.md +20 -45
  205. package/templates/skills/orc-quick/README.md +44 -3
  206. package/templates/skills/orc-quick/SKILL.md +77 -108
  207. package/templates/skills/orc-quick/references/dispatch-gate.md +18 -6
  208. package/templates/skills/orc-quick/references/gh-mode.md +50 -1
  209. package/templates/skills/orc-quick/references/look.md +3 -1
  210. package/templates/skills/orc-retro/SKILL.md +20 -19
  211. package/templates/skills/orc-retro/examples/retro-mock.md +17 -17
  212. package/templates/skills/orc-route/SKILL.md +25 -45
  213. package/templates/skills/orc-test/SKILL.md +16 -37
  214. package/templates/skills/orc-verify/SKILL.md +14 -32
  215. package/templates/skills/orc-wait/SKILL.md +156 -163
  216. package/templates/skills/orc-wiki/README.md +325 -325
  217. package/templates/skills/orc-wiki/SKILL.md +195 -195
  218. package/templates/skills/orc-wiki/examples/wiki-run-mock.md +37 -37
  219. package/templates/skills/orc-wiki/references/extra.md +2 -2
  220. package/templates/skills/orc-wiki/references/partial-refresh.md +276 -271
  221. package/templates/skills/orc-wiki/references/phases/phase-0.md +2 -7
  222. package/templates/skills/orc-wiki/references/phases/phase-1.md +1 -6
  223. package/templates/skills/orc-wiki/references/phases/phase-2.md +4 -9
  224. package/templates/skills/orc-wiki/references/phases/phase-3.md +1 -6
  225. package/templates/skills/orc-wiki/references/phases/phase-3c.md +4 -8
  226. package/templates/agents/orc-claude-writer-opus-5-med.md +0 -55
  227. package/templates/agents/orc-reviewer-opus-5-med.md +0 -60
  228. package/templates/agents/orc-wiki-scanner-opus-5-med.md +0 -81
@@ -1,126 +1,126 @@
1
- "use strict";
2
- /* 91-shortcuts.js — orc ui client
3
- Single keys, and ONLY when you are not typing into something.
4
-
5
- Loaded by app.html in the order its numeric prefix names. Classic
6
- script, no import/export: an ES module import carries no query string,
7
- and every static request here needs the per-launch session token. */
8
-
9
- /* =============================================================== shortcuts == */
10
-
11
- // Keyboard nav for a panel app that is otherwise all mouse. Deliberately small
12
- // and unmodified: single keys, and ONLY when you are not typing into something.
13
- const SHORTCUTS = () => [
14
- ["1 – 9, 0", t("shortcuts.panels")],
15
- ["d · c · p · b · h · e · m", t("shortcuts.panelsLetters")],
16
- ["/", t("shortcuts.filter")],
17
- ["r", t("shortcuts.reload")],
18
- ["t", t("shortcuts.theme")],
19
- ["l", t("shortcuts.lang")],
20
- ["?", t("shortcuts.list")],
21
- ["Esc", t("shortcuts.escape")],
22
- ];
23
-
24
- // A keystroke must never be stolen from an input, a textarea or a select — that
25
- // is how a UI eats the "r" in the middle of a path somebody is typing.
26
- function typingInto(t) {
27
- return !!t && (t.tagName === "INPUT" || t.tagName === "TEXTAREA" || t.tagName === "SELECT" || t.isContentEditable);
28
- }
29
-
30
- function showShortcuts() {
31
- const body = el("div", "stack stack-sm");
32
- const list = el("dl", "kv");
33
- for (const [key, what] of SHORTCUTS()) {
34
- const dt = el("dt");
35
- dt.append(el("kbd", null, key));
36
- list.append(dt, el("dd", null, what));
37
- }
38
- body.append(list);
39
- body.append(el("div", "note", t("shortcuts.note")));
40
- modal({
41
- title: t("shortcuts.title"),
42
- body,
43
- actions: [
44
- // Dismissing the tour must never be a one-way door: it is skippable
45
- // precisely because it can be replayed.
46
- {
47
- label: t("shortcuts.replay"),
48
- onClick: (c) => {
49
- c();
50
- startFirstRunTour(metaInfo.project_root);
51
- },
52
- },
53
- { label: t("common.close"), onClick: (c) => c() },
54
- ],
55
- });
56
- }
57
-
58
- function installShortcuts() {
59
- document.addEventListener("keydown", (e) => {
60
- if (e.metaKey || e.ctrlKey || e.altKey) return;
61
- // A dialog owns the keyboard while it is open; it has its own Esc handler.
62
- if (!$("#modal-host").hidden) return;
63
- // …and so does a blocking tour step. Its own capture-phase handler has
64
- // already swallowed the key by now; this is the second lock on the door.
65
- if (tourActive && tourActive.blocking) return;
66
- if (typingInto(e.target)) return;
67
-
68
- if (e.key >= "0" && e.key <= "9") {
69
- // Matched on data-idx, not on position: the rail's order is HTML's to
70
- // decide, and a positional lookup silently rebinds every key the moment a
71
- // panel is inserted in the middle.
72
- const target = document.querySelector('#nav a[data-idx="' + e.key + '"]');
73
- if (target) {
74
- e.preventDefault();
75
- location.hash = target.getAttribute("href");
76
- }
77
- return;
78
- }
79
- // v0.46.0: the rail outgrew ten digits, so several panels carry a LETTER key.
80
- // Same lookup, same rule — matched on data-idx, never on position — and the
81
- // letters are checked before the r/t/l actions so a rail key can never be
82
- // shadowed by one of them. Adding a panel whose letter collides with an
83
- // action would break the action; p/b/h/m/c/d were free.
84
- //
85
- // The class is derived from the rail rather than re-listed, because that is
86
- // what went wrong the first time: `c` was given to Challenge in the markup
87
- // and never added to a hardcoded `[pbhm]`, so the key did nothing and
88
- // nothing failed. A rail key now works because it is IN THE RAIL.
89
- if (/^[a-z]$/.test(e.key)) {
90
- const target = document.querySelector('#nav a[data-idx="' + e.key + '"]');
91
- if (target) {
92
- e.preventDefault();
93
- location.hash = target.getAttribute("href");
94
- return;
95
- }
96
- }
97
- if (e.key === "/") {
98
- const f = $("#settings-filter");
99
- if (f) {
100
- e.preventDefault();
101
- f.focus();
102
- f.select();
103
- }
104
- return;
105
- }
106
- if (e.key === "r") {
107
- e.preventDefault();
108
- route();
109
- return;
110
- }
111
- if (e.key === "t") {
112
- e.preventDefault();
113
- $("#theme-toggle").click();
114
- return;
115
- }
116
- if (e.key === "l") {
117
- e.preventDefault();
118
- cycleLang();
119
- return;
120
- }
121
- if (e.key === "?") {
122
- e.preventDefault();
123
- showShortcuts();
124
- }
125
- });
126
- }
1
+ "use strict";
2
+ /* 91-shortcuts.js — orc ui client
3
+ Single keys, and ONLY when you are not typing into something.
4
+
5
+ Loaded by app.html in the order its numeric prefix names. Classic
6
+ script, no import/export: an ES module import carries no query string,
7
+ and every static request here needs the per-launch session token. */
8
+
9
+ /* =============================================================== shortcuts == */
10
+
11
+ // Keyboard nav for a panel app that is otherwise all mouse. Deliberately small
12
+ // and unmodified: single keys, and ONLY when you are not typing into something.
13
+ const SHORTCUTS = () => [
14
+ ["1 – 9, 0", t("shortcuts.panels")],
15
+ ["d · c · p · b · h · e · m · u", t("shortcuts.panelsLetters")],
16
+ ["/", t("shortcuts.filter")],
17
+ ["r", t("shortcuts.reload")],
18
+ ["t", t("shortcuts.theme")],
19
+ ["l", t("shortcuts.lang")],
20
+ ["?", t("shortcuts.list")],
21
+ ["Esc", t("shortcuts.escape")],
22
+ ];
23
+
24
+ // A keystroke must never be stolen from an input, a textarea or a select — that
25
+ // is how a UI eats the "r" in the middle of a path somebody is typing.
26
+ function typingInto(t) {
27
+ return !!t && (t.tagName === "INPUT" || t.tagName === "TEXTAREA" || t.tagName === "SELECT" || t.isContentEditable);
28
+ }
29
+
30
+ function showShortcuts() {
31
+ const body = el("div", "stack stack-sm");
32
+ const list = el("dl", "kv");
33
+ for (const [key, what] of SHORTCUTS()) {
34
+ const dt = el("dt");
35
+ dt.append(el("kbd", null, key));
36
+ list.append(dt, el("dd", null, what));
37
+ }
38
+ body.append(list);
39
+ body.append(el("div", "note", t("shortcuts.note")));
40
+ modal({
41
+ title: t("shortcuts.title"),
42
+ body,
43
+ actions: [
44
+ // Dismissing the tour must never be a one-way door: it is skippable
45
+ // precisely because it can be replayed.
46
+ {
47
+ label: t("shortcuts.replay"),
48
+ onClick: (c) => {
49
+ c();
50
+ startFirstRunTour(metaInfo.project_root);
51
+ },
52
+ },
53
+ { label: t("common.close"), onClick: (c) => c() },
54
+ ],
55
+ });
56
+ }
57
+
58
+ function installShortcuts() {
59
+ document.addEventListener("keydown", (e) => {
60
+ if (e.metaKey || e.ctrlKey || e.altKey) return;
61
+ // A dialog owns the keyboard while it is open; it has its own Esc handler.
62
+ if (!$("#modal-host").hidden) return;
63
+ // …and so does a blocking tour step. Its own capture-phase handler has
64
+ // already swallowed the key by now; this is the second lock on the door.
65
+ if (tourActive && tourActive.blocking) return;
66
+ if (typingInto(e.target)) return;
67
+
68
+ if (e.key >= "0" && e.key <= "9") {
69
+ // Matched on data-idx, not on position: the rail's order is HTML's to
70
+ // decide, and a positional lookup silently rebinds every key the moment a
71
+ // panel is inserted in the middle.
72
+ const target = document.querySelector('#nav a[data-idx="' + e.key + '"]');
73
+ if (target) {
74
+ e.preventDefault();
75
+ location.hash = target.getAttribute("href");
76
+ }
77
+ return;
78
+ }
79
+ // v0.46.0: the rail outgrew ten digits, so several panels carry a LETTER key.
80
+ // Same lookup, same rule — matched on data-idx, never on position — and the
81
+ // letters are checked before the r/t/l actions so a rail key can never be
82
+ // shadowed by one of them. Adding a panel whose letter collides with an
83
+ // action would break the action; p/b/h/m/c/d were free.
84
+ //
85
+ // The class is derived from the rail rather than re-listed, because that is
86
+ // what went wrong the first time: `c` was given to Challenge in the markup
87
+ // and never added to a hardcoded `[pbhm]`, so the key did nothing and
88
+ // nothing failed. A rail key now works because it is IN THE RAIL.
89
+ if (/^[a-z]$/.test(e.key)) {
90
+ const target = document.querySelector('#nav a[data-idx="' + e.key + '"]');
91
+ if (target) {
92
+ e.preventDefault();
93
+ location.hash = target.getAttribute("href");
94
+ return;
95
+ }
96
+ }
97
+ if (e.key === "/") {
98
+ const f = $("#settings-filter");
99
+ if (f) {
100
+ e.preventDefault();
101
+ f.focus();
102
+ f.select();
103
+ }
104
+ return;
105
+ }
106
+ if (e.key === "r") {
107
+ e.preventDefault();
108
+ route();
109
+ return;
110
+ }
111
+ if (e.key === "t") {
112
+ e.preventDefault();
113
+ $("#theme-toggle").click();
114
+ return;
115
+ }
116
+ if (e.key === "l") {
117
+ e.preventDefault();
118
+ cycleLang();
119
+ return;
120
+ }
121
+ if (e.key === "?") {
122
+ e.preventDefault();
123
+ showShortcuts();
124
+ }
125
+ });
126
+ }
@@ -1,118 +1,121 @@
1
- "use strict";
2
- /* 99-boot.js — orc ui client
3
- MUST LOAD LAST. `boot()` is the one load-time call in the panel, and it reads
4
- bindings from every file above — a classic-script `const` is in TDZ until its
5
- own file has been evaluated.
6
-
7
- Loaded by app.html in the order its numeric prefix names. Classic
8
- script, no import/export: an ES module import carries no query string,
9
- and every static request here needs the per-launch session token. */
10
-
11
-
12
- /* ================================================================= startup == */
13
-
14
- async function boot() {
15
- // Language first, and English is loaded UNCONDITIONALLY: it is the fallback
16
- // table every other language falls back to, so it must exist before the first
17
- // t() call regardless of which language is selected. If even English cannot be
18
- // fetched, t() returns the key and the page is ugly but functional — never
19
- // blank, and never blocked on a file.
20
- try {
21
- DICT_EN = await loadLang("en");
22
- } catch (_) {
23
- DICT_EN = {};
24
- }
25
- let savedLang = "en";
26
- try {
27
- savedLang = localStorage.getItem(LANG_KEY) || "en";
28
- } catch (_) {}
29
- // No rerender: nothing has been routed yet, and route() is called below.
30
- await setLang(savedLang, { rerender: false });
31
-
32
- // Meta next: it names the project in the rail and tells us whether we are
33
- // looking at fixtures, which must never be mistaken for a real install.
34
- try {
35
- const meta = await api("/api/meta");
36
- metaInfo = meta;
37
- const proj = $("#rail-project");
38
- proj.textContent = meta.fixtures ? t("rail.fixtures") : meta.project_root || "";
39
- proj.title = meta.project_root || "";
40
- $("#rail-version").textContent = (meta.fixtures ? "fixtures · " : "") + "v" + (meta.version || "?");
41
-
42
- // A newer release is worth ONE quiet dot in the rail, on every panel — not a
43
- // banner, not a modal. It links to the panel that can actually install it;
44
- // it never installs anything itself.
45
- versionInfo()
46
- .then((v) => {
47
- if (!v || !v.update_available) return;
48
- const link = el("a", "rail-update", "");
49
- link.href = "#/maintenance";
50
- link.append(el("span", "dot dot-warn"), document.createTextNode(`v${v.latest} available`));
51
- link.title = `You have ${v.version}. Maintenance → upgrade installs ${v.latest}.`;
52
- $("#rail-version").after(link);
53
- })
54
- .catch(() => {});
55
- if (meta.fixtures) {
56
- const b = el("div", "banner");
57
- b.append(el("div", null, t("banner.fixtures")));
58
- $("#banners").append(b);
59
- }
60
- } catch (_) {
61
- document.body.replaceChildren(
62
- (() => {
63
- const e2 = el("div", "empty", t("banner.noToken"));
64
- e2.append(el("div", "note", t("banner.noTokenHint")));
65
- return e2;
66
- })()
67
- );
68
- return;
69
- }
70
-
71
- // Theme: dark-first, remembered, and both painted explicitly.
72
- const saved = localStorage.getItem("orc-ui-theme");
73
- if (saved) document.documentElement.setAttribute("data-theme", saved);
74
- const tt = $("#theme-toggle");
75
- const syncTheme = () => (tt.textContent = document.documentElement.getAttribute("data-theme") === "light" ? t("rail.dark") : t("rail.light"));
76
- syncTheme();
77
- tt.addEventListener("click", () => {
78
- const next = document.documentElement.getAttribute("data-theme") === "light" ? "dark" : "light";
79
- document.documentElement.setAttribute("data-theme", next);
80
- localStorage.setItem("orc-ui-theme", next);
81
- syncTheme();
82
- });
83
-
84
- // Language, right below it in the rail: the same class of control (a
85
- // per-browser display preference), so it lives in the same place and is
86
- // remembered the same way. It never touches project config.
87
- const lb = $("#lang-toggle");
88
- if (lb) lb.addEventListener("click", cycleLang);
89
- applyStaticText();
90
-
91
- installShortcuts();
92
- const help = $("#shortcut-hint");
93
- if (help) help.addEventListener("click", showShortcuts);
94
-
95
- window.addEventListener("hashchange", route);
96
- route();
97
-
98
- // First run for THIS project → the tour. Fixture mode is excluded: a tour of
99
- // canned data would teach the panel using numbers that are not real.
100
- if (!metaInfo.fixtures && !tourSeen(metaInfo.project_root)) {
101
- // Let the first panel finish its fetch, so step one has something to point
102
- // at rather than a skeleton.
103
- setTimeout(() => startFirstRunTour(metaInfo.project_root), 600);
104
- }
105
-
106
- // Heartbeat: no ping from any client for 60s and the server exits, so closing
107
- // this tab shuts down a write surface instead of leaving it holding a token.
108
- const ping = () => api("/api/ping").catch(() => {});
109
- ping();
110
- setInterval(ping, 15000);
111
- window.addEventListener("beforeunload", () => {
112
- try {
113
- navigator.sendBeacon("/api/bye?t=" + encodeURIComponent(TOKEN));
114
- } catch (_) {}
115
- });
116
- }
117
-
118
- boot();
1
+ "use strict";
2
+ /* 99-boot.js — orc ui client
3
+ MUST LOAD LAST. `boot()` is the one load-time call in the panel, and it reads
4
+ bindings from every file above — a classic-script `const` is in TDZ until its
5
+ own file has been evaluated.
6
+
7
+ Loaded by app.html in the order its numeric prefix names. Classic
8
+ script, no import/export: an ES module import carries no query string,
9
+ and every static request here needs the per-launch session token. */
10
+
11
+
12
+ /* ================================================================= startup == */
13
+
14
+ async function boot() {
15
+ // Language first, and English is loaded UNCONDITIONALLY: it is the fallback
16
+ // table every other language falls back to, so it must exist before the first
17
+ // t() call regardless of which language is selected. If even English cannot be
18
+ // fetched, t() returns the key and the page is ugly but functional — never
19
+ // blank, and never blocked on a file.
20
+ try {
21
+ DICT_EN = await loadLang("en");
22
+ } catch (_) {
23
+ DICT_EN = {};
24
+ }
25
+ let savedLang = "en";
26
+ try {
27
+ savedLang = localStorage.getItem(LANG_KEY) || "en";
28
+ } catch (_) {}
29
+ // No rerender: nothing has been routed yet, and route() is called below.
30
+ await setLang(savedLang, { rerender: false });
31
+
32
+ // Meta next: it names the project in the rail and tells us whether we are
33
+ // looking at fixtures, which must never be mistaken for a real install.
34
+ try {
35
+ const meta = await api("/api/meta");
36
+ metaInfo = meta;
37
+ const proj = $("#rail-project");
38
+ proj.textContent = meta.fixtures ? t("rail.fixtures") : meta.project_root || "";
39
+ proj.title = meta.project_root || "";
40
+ $("#rail-version").textContent = (meta.fixtures ? "fixtures · " : "") + "v" + (meta.version || "?");
41
+
42
+ // A newer release is worth ONE quiet dot in the rail, on every panel — not a
43
+ // banner, not a modal. It links to the panel that can actually install it;
44
+ // it never installs anything itself.
45
+ versionInfo()
46
+ .then((v) => {
47
+ if (!v || !v.update_available) return;
48
+ const link = el("a", "rail-update", "");
49
+ link.href = "#/maintenance";
50
+ link.append(el("span", "dot dot-warn"), document.createTextNode(`v${v.latest} available`));
51
+ link.title = `You have ${v.version}. Maintenance → upgrade installs ${v.latest}.`;
52
+ $("#rail-version").after(link);
53
+ })
54
+ .catch(() => {});
55
+ if (meta.fixtures) {
56
+ const b = el("div", "banner");
57
+ b.append(el("div", null, t("banner.fixtures")));
58
+ $("#banners").append(b);
59
+ }
60
+ } catch (_) {
61
+ document.body.replaceChildren(
62
+ (() => {
63
+ const e2 = el("div", "empty", t("banner.noToken"));
64
+ e2.append(el("div", "note", t("banner.noTokenHint")));
65
+ return e2;
66
+ })()
67
+ );
68
+ return;
69
+ }
70
+
71
+ // Theme: dark-first, remembered, and both painted explicitly.
72
+ const saved = localStorage.getItem("orc-ui-theme");
73
+ if (saved) document.documentElement.setAttribute("data-theme", saved);
74
+ const tt = $("#theme-toggle");
75
+ const syncTheme = () => (tt.textContent = document.documentElement.getAttribute("data-theme") === "light" ? t("rail.dark") : t("rail.light"));
76
+ syncTheme();
77
+ tt.addEventListener("click", () => {
78
+ const next = document.documentElement.getAttribute("data-theme") === "light" ? "dark" : "light";
79
+ document.documentElement.setAttribute("data-theme", next);
80
+ localStorage.setItem("orc-ui-theme", next);
81
+ syncTheme();
82
+ });
83
+
84
+ // Language, right below it in the rail: the same class of control (a
85
+ // per-browser display preference), so it lives in the same place and is
86
+ // remembered the same way. It never touches project config.
87
+ const lb = $("#lang-toggle");
88
+ if (lb) lb.addEventListener("click", cycleLang);
89
+ applyStaticText();
90
+
91
+ installShortcuts();
92
+ const help = $("#shortcut-hint");
93
+ if (help) help.addEventListener("click", showShortcuts);
94
+
95
+ window.addEventListener("hashchange", route);
96
+ route();
97
+ // v2.0.0 W7 — a waiting habit proposal is ONE quiet dot on the Behaviour rail
98
+ // link. It is the only place outside that panel that shows habit state.
99
+ behaviourRailDot();
100
+
101
+ // First run for THIS project → the tour. Fixture mode is excluded: a tour of
102
+ // canned data would teach the panel using numbers that are not real.
103
+ if (!metaInfo.fixtures && !tourSeen(metaInfo.project_root)) {
104
+ // Let the first panel finish its fetch, so step one has something to point
105
+ // at rather than a skeleton.
106
+ setTimeout(() => startFirstRunTour(metaInfo.project_root), 600);
107
+ }
108
+
109
+ // Heartbeat: no ping from any client for 60s and the server exits, so closing
110
+ // this tab shuts down a write surface instead of leaving it holding a token.
111
+ const ping = () => api("/api/ping").catch(() => {});
112
+ ping();
113
+ setInterval(ping, 15000);
114
+ window.addEventListener("beforeunload", () => {
115
+ try {
116
+ navigator.sendBeacon("/api/bye?t=" + encodeURIComponent(TOKEN));
117
+ } catch (_) {}
118
+ });
119
+ }
120
+
121
+ boot();