@worca/app 1.0.0 → 1.1.1

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 (138) hide show
  1. package/README.md +22 -9
  2. package/agents/clarify.meta.json +4 -4
  3. package/agents/decomposer.meta.json +5 -5
  4. package/agents/implementer.meta.json +15 -5
  5. package/agents/manualTestsChecklist.meta.json +5 -4
  6. package/agents/manualWebUiTesting.meta.json +9 -4
  7. package/agents/planReviewer.meta.json +12 -4
  8. package/agents/planner.meta.json +12 -5
  9. package/agents/refiner.meta.json +15 -4
  10. package/agents/reviewer.meta.json +14 -4
  11. package/agents/worca-cc-clarify.md +7 -0
  12. package/agents/worca-cc-code-reviewer.md +11 -6
  13. package/agents/worca-cc-decomposer.md +7 -0
  14. package/agents/worca-cc-implementer.md +9 -0
  15. package/agents/worca-cc-manual-tests-checklist.md +8 -5
  16. package/agents/worca-cc-manual-web-ui-testing.md +10 -6
  17. package/agents/worca-cc-plan-refiner.md +11 -6
  18. package/agents/worca-cc-plan-reviewer.md +10 -7
  19. package/agents/worca-cc-planner.md +9 -0
  20. package/agents/worca-cc-workspace-reviewer.md +11 -4
  21. package/agents/worca-cc-workspace-scanner.md +8 -4
  22. package/agents/workspaceReviewer.meta.json +15 -4
  23. package/agents/workspaceScanner.meta.json +5 -4
  24. package/package.json +8 -2
  25. package/skills/worca/SKILL.md +5 -5
  26. package/src/cli/render.mjs +148 -0
  27. package/src/cli/worca-cc.mjs +319 -45
  28. package/src/core/agent-gen.mjs +69 -31
  29. package/src/core/agent-registry.mjs +124 -144
  30. package/src/core/agent-store.mjs +164 -4
  31. package/src/core/artifacts.mjs +189 -21
  32. package/src/core/ask/catalog.mjs +111 -0
  33. package/src/core/ask/comment-deps.mjs +55 -0
  34. package/src/core/ask/events.mjs +506 -0
  35. package/src/core/ask/follow.mjs +107 -0
  36. package/src/core/ask/git-allowlist.mjs +226 -0
  37. package/src/core/ask/limits.mjs +54 -0
  38. package/src/core/ask/mcp-stdio.mjs +135 -0
  39. package/src/core/ask/models.mjs +125 -0
  40. package/src/core/ask/prompt.mjs +261 -0
  41. package/src/core/ask/proposal.mjs +170 -0
  42. package/src/core/ask/redact.mjs +30 -0
  43. package/src/core/ask/spawn.mjs +153 -0
  44. package/src/core/ask/store.mjs +360 -0
  45. package/src/core/ask/tool-deps.mjs +63 -0
  46. package/src/core/ask/tools.mjs +848 -0
  47. package/src/core/ask/turn.mjs +416 -0
  48. package/src/core/ask/worktree-deps.mjs +27 -0
  49. package/src/core/ask/worktrees.mjs +285 -0
  50. package/src/core/chat/command-router.mjs +20 -3
  51. package/src/core/claude-runner.mjs +434 -57
  52. package/src/core/config.mjs +264 -41
  53. package/src/core/cost-budget.mjs +29 -2
  54. package/src/core/db.mjs +684 -47
  55. package/src/core/diff-anchor.mjs +213 -0
  56. package/src/core/diff-comments.mjs +273 -0
  57. package/src/core/engine-select.mjs +32 -0
  58. package/src/core/git-info.mjs +49 -10
  59. package/src/core/graph/builtin-workflows.mjs +51 -0
  60. package/src/core/graph/executor.mjs +894 -0
  61. package/src/core/graph/registry-ports.mjs +12 -0
  62. package/src/core/graph/scheduler.mjs +1065 -0
  63. package/src/core/graph/seed-templates.mjs +318 -0
  64. package/src/core/model-env.mjs +112 -8
  65. package/src/core/model-test.mjs +79 -0
  66. package/src/core/orchestrator.mjs +902 -4098
  67. package/src/core/overview-agent.mjs +15 -3
  68. package/src/core/phases.mjs +208 -537
  69. package/src/core/pipeline-delete.mjs +13 -2
  70. package/src/core/plugin-api.mjs +8 -3
  71. package/src/core/plugin-config.mjs +178 -28
  72. package/src/core/plugin-inventory.mjs +6 -2
  73. package/src/core/plugin-manifest.mjs +199 -11
  74. package/src/core/plugin-models.mjs +1 -0
  75. package/src/core/plugin-repo.mjs +16 -4
  76. package/src/core/plugin-shim-child.mjs +9 -3
  77. package/src/core/plugin-shim.mjs +77 -14
  78. package/src/core/plugin-store.mjs +236 -29
  79. package/src/core/plugin-workflows.mjs +90 -41
  80. package/src/core/preflight.mjs +135 -3
  81. package/src/core/projects.mjs +7 -5
  82. package/src/core/protocol.mjs +8 -35
  83. package/src/core/recoverable-error.mjs +1 -1
  84. package/src/core/run-harness.mjs +3585 -0
  85. package/src/core/run-manifest.mjs +5 -1
  86. package/src/core/settings.mjs +109 -13
  87. package/src/core/skills.mjs +10 -3
  88. package/src/core/source-bindings.mjs +175 -0
  89. package/src/core/sources.mjs +87 -25
  90. package/src/core/stats.mjs +25 -6
  91. package/src/core/title.mjs +51 -4
  92. package/src/core/workflows.mjs +358 -259
  93. package/src/core/workspace-scan.mjs +4 -0
  94. package/src/core/worktree.mjs +98 -7
  95. package/src/shared/graph/agent-meta.mjs +278 -0
  96. package/src/shared/graph/constants.mjs +105 -0
  97. package/src/shared/graph/geometry.mjs +157 -0
  98. package/src/shared/graph/layout.mjs +134 -0
  99. package/src/shared/graph/loops.mjs +130 -0
  100. package/src/shared/graph/manifest.mjs +257 -0
  101. package/src/shared/graph/ports.mjs +153 -0
  102. package/src/shared/graph/route.mjs +397 -0
  103. package/src/shared/graph/template.mjs +165 -0
  104. package/src/shared/graph/thumbnail.mjs +67 -0
  105. package/src/shared/graph/validate.mjs +491 -0
  106. package/src/shared/graph/verdict.mjs +41 -0
  107. package/ui/public/app.js +4008 -1670
  108. package/ui/public/ask-markdown.mjs +145 -0
  109. package/ui/public/ask-model.mjs +264 -0
  110. package/ui/public/ask-panel.mjs +1880 -0
  111. package/ui/public/chat-settings-view.mjs +6 -2
  112. package/ui/public/diff-view.mjs +66 -11
  113. package/ui/public/file-tree.mjs +305 -0
  114. package/ui/public/graph/composer.mjs +889 -0
  115. package/ui/public/graph/inspector.mjs +183 -0
  116. package/ui/public/graph/model.mjs +37 -0
  117. package/ui/public/graph/palette.mjs +144 -0
  118. package/ui/public/graph/run-decor.mjs +410 -0
  119. package/ui/public/graph/run-hosts.mjs +201 -0
  120. package/ui/public/graph/save-dialog.mjs +56 -0
  121. package/ui/public/graph/view.mjs +858 -0
  122. package/ui/public/guardrails-view.mjs +4 -2
  123. package/ui/public/hljs-loader.mjs +180 -0
  124. package/ui/public/index.html +269 -265
  125. package/ui/public/log-filter.mjs +22 -4
  126. package/ui/public/log-line.mjs +45 -19
  127. package/ui/public/models-view.mjs +171 -9
  128. package/ui/public/plugins-view.mjs +106 -4
  129. package/ui/public/source-pane.mjs +190 -8
  130. package/ui/public/stats-view.mjs +81 -1
  131. package/ui/public/style.css +1459 -229
  132. package/ui/public/syntax-highlight.mjs +270 -0
  133. package/ui/public/thinking-orb.mjs +110 -0
  134. package/ui/server.mjs +1667 -98
  135. package/src/core/channels.mjs +0 -302
  136. package/src/core/runners.mjs +0 -167
  137. package/src/core/workflow-validator.mjs +0 -185
  138. package/ui/public/composer-core.mjs +0 -211
@@ -71,14 +71,16 @@ export function renderStartStep(sources, { doc = globalThis.document, selectedId
71
71
  list.setAttribute('role', 'radiogroup');
72
72
  list.setAttribute('aria-label', 'Starting point');
73
73
  const addRow = (id, label, builtin) => {
74
- const row = h(doc, 'label', 'grv-source-row');
74
+ // .opt-row carries the selection on the WHOLE row (the name and its badge
75
+ // travel together); .grv-source-row stays for this view's own layout.
76
+ const row = h(doc, 'label', 'grv-source-row opt-row');
75
77
  const radio = h(doc, 'input', 'grv-source');
76
78
  radio.type = 'radio';
77
79
  radio.name = 'grv-source';
78
80
  radio.value = id;
79
81
  if (id === selectedId) radio.checked = true;
80
82
  row.appendChild(radio);
81
- row.appendChild(h(doc, 'span', 'grv-source-name', label));
83
+ row.appendChild(h(doc, 'span', 'grv-source-name opt-name', label));
82
84
  if (builtin) row.appendChild(h(doc, 'span', 'badge waiting', 'built-in'));
83
85
  list.appendChild(row);
84
86
  };
@@ -0,0 +1,180 @@
1
+ import { SUPPORTED_LANGUAGE_IDS } from './syntax-highlight.mjs';
2
+
3
+ const LANGUAGE_ID_RE = /^[a-z0-9][a-z0-9-]{0,63}$/;
4
+ const ALLOWED_LANGUAGES = new Set(SUPPORTED_LANGUAGE_IDS);
5
+ const codeUnitCompare = (a, b) => (a < b ? -1 : a > b ? 1 : 0);
6
+
7
+ // Grammars the pinned highlight.js build delegates to through `subLanguage`
8
+ // regions (JSX markup inside javascript/typescript, <script>/<style> bodies
9
+ // inside xml, RUN arguments in dockerfile, …), closed transitively: xml's
10
+ // <style> body needs css even when xml itself is only reached from javascript.
11
+ // Core emits a region as PLAIN TEXT when its grammar is missing from the
12
+ // instance, so every primary language registers its whole closure up front.
13
+ // The set is fixed per primary language, which keeps the output a pure
14
+ // function of (language, text) rather than of which files were opened first.
15
+ // Every declared sub-language is a string (never an autodetect list), so the
16
+ // extra grammars can only fill those regions, never change the primary parse.
17
+ // test/hljs-loader.test.mjs derives this table from the installed package and
18
+ // fails on drift after an upgrade.
19
+ export const HLJS_SUB_LANGUAGES = Object.freeze({
20
+ dart: Object.freeze(['css', 'graphql', 'javascript', 'markdown', 'xml']),
21
+ dockerfile: Object.freeze(['bash']),
22
+ javascript: Object.freeze(['css', 'graphql', 'xml']),
23
+ markdown: Object.freeze(['css', 'graphql', 'javascript', 'xml']),
24
+ nix: Object.freeze(['css', 'graphql', 'javascript', 'markdown', 'xml']),
25
+ perl: Object.freeze(['css', 'graphql', 'javascript', 'mojolicious', 'xml']),
26
+ typescript: Object.freeze(['css', 'graphql', 'javascript', 'xml']),
27
+ xml: Object.freeze(['css', 'graphql', 'javascript']),
28
+ yaml: Object.freeze(['ruby']),
29
+ });
30
+
31
+ const subLanguagesOf = (lang) => (
32
+ Object.hasOwn(HLJS_SUB_LANGUAGES, lang) ? HLJS_SUB_LANGUAGES[lang] : []
33
+ );
34
+
35
+ // Every grammar file the loader may request: the reviewed primaries plus their
36
+ // sub-languages. ui/server.mjs serves exactly this set under /vendor/hljs.
37
+ export const HLJS_GRAMMAR_IDS = Object.freeze(
38
+ [...new Set([...SUPPORTED_LANGUAGE_IDS, ...Object.values(HLJS_SUB_LANGUAGES).flat()])]
39
+ .sort(codeUnitCompare),
40
+ );
41
+ // Retry-on-next-call exists for a blip (a server restart mid-session), not for
42
+ // a /vendor that fails forever: without a ceiling every selection costs one
43
+ // doomed import per missing resource, one console error each, and a new
44
+ // `?retry=N` entry in the module map. After this many failed loads of a
45
+ // resource the loader answers null for the rest of the page's life.
46
+ export const MAX_RESOURCE_FAILURES = 3;
47
+ const coreUrl = (attempt) => `/vendor/hljs/core.min.js?retry=${attempt}`;
48
+ const grammarUrl = (lang, attempt) =>
49
+ `/vendor/hljs/languages/${lang}.min.js?retry=${attempt}`;
50
+
51
+ export function createHljsLoader(options = {}) {
52
+ const loadCore = options.loadCore || ((attempt) => import(coreUrl(attempt)));
53
+ const loadGrammar = options.loadGrammar
54
+ || ((lang, attempt) => import(grammarUrl(lang, attempt)));
55
+
56
+ let coreFactory = null;
57
+ let corePending = null;
58
+ let nextCoreAttempt = 0;
59
+ let coreFailures = 0;
60
+ const grammarPending = new Map();
61
+ const grammarFunctions = new Map();
62
+ const nextGrammarAttempt = new Map();
63
+ const grammarFailures = new Map();
64
+ const languagePending = new Map();
65
+ const languageReady = new Map();
66
+
67
+ const validInstance = (value) => value
68
+ && typeof value.getLanguage === 'function'
69
+ && typeof value.registerLanguage === 'function'
70
+ && typeof value.highlight === 'function';
71
+
72
+ function getCoreFactory() {
73
+ if (coreFactory) return Promise.resolve(coreFactory);
74
+ if (corePending) return corePending;
75
+ if (coreFailures >= MAX_RESOURCE_FAILURES) return Promise.resolve(null);
76
+ const attempt = nextCoreAttempt++;
77
+ const pending = Promise.resolve()
78
+ .then(() => loadCore(attempt))
79
+ .then((mod) => {
80
+ const exported = mod?.default;
81
+ if (typeof exported?.newInstance !== 'function') {
82
+ throw new TypeError('core module has no newInstance factory');
83
+ }
84
+ coreFactory = exported;
85
+ return coreFactory;
86
+ })
87
+ .catch(() => {
88
+ coreFailures += 1;
89
+ return null;
90
+ })
91
+ .finally(() => {
92
+ if (corePending === pending) corePending = null;
93
+ });
94
+ corePending = pending;
95
+ return pending;
96
+ }
97
+
98
+ function getGrammar(lang) {
99
+ if (grammarFunctions.has(lang)) return Promise.resolve(grammarFunctions.get(lang));
100
+ const existing = grammarPending.get(lang);
101
+ if (existing) return existing;
102
+ if ((grammarFailures.get(lang) || 0) >= MAX_RESOURCE_FAILURES) return Promise.resolve(null);
103
+ const attempt = nextGrammarAttempt.get(lang) || 0;
104
+ nextGrammarAttempt.set(lang, attempt + 1);
105
+ const pending = Promise.resolve()
106
+ .then(() => loadGrammar(lang, attempt))
107
+ .then((mod) => {
108
+ if (typeof mod?.default !== 'function') throw new TypeError('invalid grammar module');
109
+ grammarFunctions.set(lang, mod.default);
110
+ return mod.default;
111
+ })
112
+ .catch(() => {
113
+ grammarFailures.set(lang, (grammarFailures.get(lang) || 0) + 1);
114
+ return null;
115
+ })
116
+ .finally(() => {
117
+ if (grammarPending.get(lang) === pending) grammarPending.delete(lang);
118
+ });
119
+ grammarPending.set(lang, pending);
120
+ return pending;
121
+ }
122
+
123
+ function buildLanguage(lang) {
124
+ if (languageReady.has(lang)) return Promise.resolve(languageReady.get(lang));
125
+ const existing = languagePending.get(lang);
126
+ if (existing) return existing;
127
+ const subs = subLanguagesOf(lang);
128
+ const pending = Promise.all([getCoreFactory(), getGrammar(lang), ...subs.map(getGrammar)])
129
+ .then(([factory, grammar, ...subGrammars]) => {
130
+ // All-or-nothing: a binding is cached only when its whole closure
131
+ // loaded, so a transient grammar failure degrades to plain rows now
132
+ // and retries just that grammar on the next selection — it never
133
+ // yields a cached binding whose output depends on what happened to load.
134
+ if (!factory || !grammar || subGrammars.some((sub) => !sub)) return null;
135
+ const hljs = factory.newInstance();
136
+ if (!validInstance(hljs)) throw new TypeError('invalid highlight.js instance');
137
+ hljs.registerLanguage(lang, grammar);
138
+ subs.forEach((sub, index) => hljs.registerLanguage(sub, subGrammars[index]));
139
+ if (![lang, ...subs].every((id) => hljs.getLanguage(id))) {
140
+ throw new TypeError('grammar did not register');
141
+ }
142
+ const bound = Object.freeze({
143
+ lang,
144
+ highlight(text, requested = lang) {
145
+ if (requested !== lang) throw new TypeError('language mismatch');
146
+ const result = hljs.highlight(String(text), {
147
+ language: lang,
148
+ ignoreIllegals: true,
149
+ });
150
+ if (typeof result?.value !== 'string') {
151
+ throw new TypeError('invalid highlight result');
152
+ }
153
+ return result.value;
154
+ },
155
+ });
156
+ languageReady.set(lang, bound);
157
+ return bound;
158
+ })
159
+ .catch(() => null)
160
+ .finally(() => {
161
+ if (languagePending.get(lang) === pending) languagePending.delete(lang);
162
+ });
163
+ languagePending.set(lang, pending);
164
+ return pending;
165
+ }
166
+
167
+ return Object.freeze({
168
+ async forLanguage(input) {
169
+ try {
170
+ const lang = String(input ?? '');
171
+ if (!LANGUAGE_ID_RE.test(lang) || !ALLOWED_LANGUAGES.has(lang)) return null;
172
+ return await buildLanguage(lang);
173
+ } catch {
174
+ return null;
175
+ }
176
+ },
177
+ });
178
+ }
179
+
180
+ export const _testing = Object.freeze({ coreUrl, grammarUrl });