@worca/app 1.0.0 → 1.2.0-rc.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 (143) hide show
  1. package/README.md +30 -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 +386 -56
  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 +199 -23
  32. package/src/core/ask/attachment-kind.mjs +95 -0
  33. package/src/core/ask/catalog.mjs +111 -0
  34. package/src/core/ask/comment-deps.mjs +55 -0
  35. package/src/core/ask/events.mjs +545 -0
  36. package/src/core/ask/follow.mjs +113 -0
  37. package/src/core/ask/git-allowlist.mjs +226 -0
  38. package/src/core/ask/limits.mjs +57 -0
  39. package/src/core/ask/mcp-stdio.mjs +135 -0
  40. package/src/core/ask/models.mjs +125 -0
  41. package/src/core/ask/prompt.mjs +286 -0
  42. package/src/core/ask/proposal.mjs +170 -0
  43. package/src/core/ask/redact.mjs +30 -0
  44. package/src/core/ask/spawn.mjs +156 -0
  45. package/src/core/ask/store.mjs +438 -0
  46. package/src/core/ask/tool-deps.mjs +87 -0
  47. package/src/core/ask/tools.mjs +879 -0
  48. package/src/core/ask/turn.mjs +462 -0
  49. package/src/core/ask/worktree-deps.mjs +27 -0
  50. package/src/core/ask/worktrees.mjs +285 -0
  51. package/src/core/chat/command-router.mjs +28 -7
  52. package/src/core/chat/notifier.mjs +6 -1
  53. package/src/core/chat/renderers.mjs +15 -8
  54. package/src/core/claude-runner.mjs +541 -62
  55. package/src/core/config.mjs +310 -44
  56. package/src/core/cost-budget.mjs +29 -2
  57. package/src/core/db.mjs +773 -53
  58. package/src/core/diff-anchor.mjs +213 -0
  59. package/src/core/diff-comments.mjs +273 -0
  60. package/src/core/engine-select.mjs +32 -0
  61. package/src/core/failure-policy.mjs +201 -0
  62. package/src/core/git-info.mjs +49 -10
  63. package/src/core/graph/builtin-workflows.mjs +51 -0
  64. package/src/core/graph/executor.mjs +894 -0
  65. package/src/core/graph/registry-ports.mjs +12 -0
  66. package/src/core/graph/scheduler.mjs +1072 -0
  67. package/src/core/graph/seed-templates.mjs +318 -0
  68. package/src/core/host-guard.mjs +271 -0
  69. package/src/core/model-env.mjs +180 -8
  70. package/src/core/model-test.mjs +79 -0
  71. package/src/core/orchestrator.mjs +994 -4097
  72. package/src/core/overview-agent.mjs +15 -3
  73. package/src/core/phases.mjs +208 -537
  74. package/src/core/pipeline-delete.mjs +13 -2
  75. package/src/core/plugin-api.mjs +8 -3
  76. package/src/core/plugin-config.mjs +178 -28
  77. package/src/core/plugin-inventory.mjs +6 -2
  78. package/src/core/plugin-manifest.mjs +199 -11
  79. package/src/core/plugin-models.mjs +1 -0
  80. package/src/core/plugin-repo.mjs +16 -4
  81. package/src/core/plugin-shim-child.mjs +9 -3
  82. package/src/core/plugin-shim.mjs +80 -17
  83. package/src/core/plugin-store.mjs +236 -29
  84. package/src/core/plugin-workflows.mjs +90 -41
  85. package/src/core/preflight.mjs +135 -3
  86. package/src/core/projects.mjs +7 -5
  87. package/src/core/protocol.mjs +8 -35
  88. package/src/core/recoverable-error.mjs +1 -1
  89. package/src/core/run-harness.mjs +3934 -0
  90. package/src/core/run-manifest.mjs +5 -1
  91. package/src/core/settings.mjs +184 -13
  92. package/src/core/skills.mjs +10 -3
  93. package/src/core/source-bindings.mjs +175 -0
  94. package/src/core/sources.mjs +87 -25
  95. package/src/core/stats.mjs +25 -6
  96. package/src/core/title.mjs +51 -4
  97. package/src/core/workflows.mjs +358 -259
  98. package/src/core/workspace-scan.mjs +4 -0
  99. package/src/core/worktree.mjs +98 -7
  100. package/src/shared/graph/agent-meta.mjs +278 -0
  101. package/src/shared/graph/constants.mjs +105 -0
  102. package/src/shared/graph/geometry.mjs +157 -0
  103. package/src/shared/graph/layout.mjs +134 -0
  104. package/src/shared/graph/loops.mjs +130 -0
  105. package/src/shared/graph/manifest.mjs +257 -0
  106. package/src/shared/graph/ports.mjs +153 -0
  107. package/src/shared/graph/route.mjs +397 -0
  108. package/src/shared/graph/template.mjs +165 -0
  109. package/src/shared/graph/thumbnail.mjs +67 -0
  110. package/src/shared/graph/validate.mjs +491 -0
  111. package/src/shared/graph/verdict.mjs +41 -0
  112. package/ui/public/app.js +4240 -1682
  113. package/ui/public/ask-markdown.mjs +145 -0
  114. package/ui/public/ask-model.mjs +317 -0
  115. package/ui/public/ask-panel.mjs +2129 -0
  116. package/ui/public/chat-settings-view.mjs +6 -2
  117. package/ui/public/diff-view.mjs +66 -11
  118. package/ui/public/file-tree.mjs +305 -0
  119. package/ui/public/graph/composer.mjs +889 -0
  120. package/ui/public/graph/inspector.mjs +183 -0
  121. package/ui/public/graph/model.mjs +37 -0
  122. package/ui/public/graph/palette.mjs +144 -0
  123. package/ui/public/graph/run-decor.mjs +410 -0
  124. package/ui/public/graph/run-hosts.mjs +201 -0
  125. package/ui/public/graph/save-dialog.mjs +56 -0
  126. package/ui/public/graph/view.mjs +858 -0
  127. package/ui/public/guardrails-view.mjs +4 -2
  128. package/ui/public/hljs-loader.mjs +180 -0
  129. package/ui/public/index.html +311 -265
  130. package/ui/public/log-filter.mjs +22 -4
  131. package/ui/public/log-line.mjs +45 -19
  132. package/ui/public/models-view.mjs +171 -9
  133. package/ui/public/plugins-view.mjs +106 -4
  134. package/ui/public/source-pane.mjs +190 -8
  135. package/ui/public/stats-view.mjs +81 -1
  136. package/ui/public/style.css +1487 -229
  137. package/ui/public/syntax-highlight.mjs +270 -0
  138. package/ui/public/thinking-orb.mjs +110 -0
  139. package/ui/server.mjs +1894 -104
  140. package/src/core/channels.mjs +0 -302
  141. package/src/core/runners.mjs +0 -167
  142. package/src/core/workflow-validator.mjs +0 -185
  143. package/ui/public/composer-core.mjs +0 -211
@@ -1,211 +0,0 @@
1
- // ui/public/composer-core.mjs
2
- // Framework-free, DOM-free helpers for the Pipeline Composer. Imported by
3
- // ui/public/app.js (browser, type="module") AND by test/composer-ui.test.mjs
4
- // (node:test, no jsdom). KEEP THIS FILE FREE OF document/window references so it
5
- // stays unit-testable in isolation — DOM wiring lives in app.js.
6
-
7
- // ---------------------------------------------------------------------------
8
- // topology(steps, feedbacks) -> WorkflowTemplate {steps,feedbacks} body.
9
- // Canvas model uses throwaway local ids (n1, n7…). The persisted contract uses
10
- // stable instance ids "s{stepIndex}_{memberIndex}" (e.g. "s0_0"); feedback
11
- // from/to reference those instance ids. We rebuild the id map and remap edges,
12
- // dropping any edge whose endpoint is gone (defensive; the UI prunes these too).
13
- // ---------------------------------------------------------------------------
14
- export function topology(steps, feedbacks) {
15
- const idMap = {}; // localId -> "sI_J"
16
- const outSteps = steps.map((col, i) =>
17
- col.map((node, j) => {
18
- const id = `s${i}_${j}`;
19
- idMap[node.id] = id;
20
- return { id, key: node.key };
21
- }),
22
- );
23
- const outFeedbacks = [];
24
- (feedbacks || []).forEach((fb) => {
25
- const from = idMap[fb.from];
26
- const to = idMap[fb.to];
27
- if (from && to) outFeedbacks.push({ id: `fb_${outFeedbacks.length}`, from, to });
28
- });
29
- return { steps: outSteps, feedbacks: outFeedbacks };
30
- }
31
-
32
- // metaLine(steps, feedbacks) -> "N steps · M agents[ · K feedback loop(s)]"
33
- // (saved-pipelines card meta line). Mirrors the mockup's renderList meta string.
34
- export function metaLine(steps, feedbacks) {
35
- const nSteps = steps.length;
36
- const nAgents = steps.reduce((sum, col) => sum + col.length, 0);
37
- const nLoops = (feedbacks || []).length;
38
- let s = `${nSteps} steps · ${nAgents} agents`;
39
- if (nLoops) s += ` · ${nLoops} feedback loop${nLoops > 1 ? 's' : ''}`;
40
- return s;
41
- }
42
-
43
- // distinctAgents(steps) -> ordered unique role keys (for the chip row).
44
- export function distinctAgents(steps) {
45
- const seen = [];
46
- steps.forEach((col) => col.forEach((node) => {
47
- if (!seen.includes(node.key)) seen.push(node.key);
48
- }));
49
- return seen;
50
- }
51
-
52
- // Embedded agent registry — fallback for the palette when /api/agents is
53
- // unavailable (e.g. a sibling phase's endpoint not yet wired). Keys are the
54
- // canonical camelCase agent keys; icon = inner SVG markup, viewBox "0 0 24 24"
55
- // (glyphs copied from the standalone mockup's ICON map). The live registry from
56
- // GET /api/agents overrides this whenever present (see mergePalette).
57
- export const EMBEDDED_AGENTS = {
58
- clarify: {
59
- key: 'clarify', displayName: 'Clarify', description: 'Turns hidden decisions into questions before planning. Multiple-choice, so later steps never guess.',
60
- color: 'red', order: 0, connectsTo: ['planner'],
61
- icon: '<circle cx="12" cy="12" r="9"/><path d="M9.4 9.3a2.7 2.7 0 0 1 5.2 1c0 1.8-2.6 2.1-2.6 3.6" stroke-linecap="round" fill="none"/><circle cx="12" cy="17" r="0.7" fill="currentColor" stroke="none"/>',
62
- },
63
- planner: {
64
- key: 'planner', displayName: 'Plan', description: 'Explores the codebase and writes the implementation plan. Architecture, task breakdown, concrete code snippets; can ask clarifying questions first.',
65
- color: 'violet', order: 1, connectsTo: ['refiner', 'implementer', 'decomposer'],
66
- icon: '<path d="M8 6h11M8 12h11M8 18h8" stroke-linecap="round"/><circle cx="4" cy="6" r="1.1"/><circle cx="4" cy="12" r="1.1"/><circle cx="4" cy="18" r="1.1"/>',
67
- },
68
- refiner: {
69
- key: 'refiner', displayName: 'Refine Plan', description: 'Rewrites the latest plan into a tighter version. Fixes structure, correctness, and code snippets until no blocking issues remain.',
70
- color: 'green', order: 2, connectsTo: ['implementer', 'refiner', 'decomposer'],
71
- icon: '<path d="M12 3v3M12 18v3M4.5 7.5l2 1M17.5 15.5l2 1M4.5 16.5l2-1M17.5 8.5l2-1" stroke-linecap="round"/><path d="M12 8.2l1.2 2.6L16 12l-2.8 1.2L12 15.8l-1.2-2.6L8 12l2.8-1.2L12 8.2Z" stroke-linejoin="round"/>',
72
- },
73
- decomposer: {
74
- key: 'decomposer', displayName: 'Decompose', description: 'Splits an approved plan into vertical-slice tasks. Each task gets its own implementer.',
75
- color: 'blue', order: 2.5, connectsTo: ['implementer'],
76
- },
77
- implementer: {
78
- key: 'implementer', displayName: 'Implementation', description: 'Writes the code from the approved plan, strict TDD. In fix mode, addresses only the issues a review flagged.',
79
- color: 'peach', order: 3, connectsTo: ['reviewer', 'manualTestsChecklist'],
80
- icon: '<path d="M9 8l-4 4 4 4M15 8l4 4-4 4" stroke-linecap="round" stroke-linejoin="round"/>',
81
- },
82
- reviewer: {
83
- key: 'reviewer', displayName: 'Review Implementation', description: 'Reviews the implementation diff against the plan. Honest verdict; blocking findings loop back to the implementer.',
84
- color: 'blue', order: 4, connectsTo: ['implementer', 'manualTestsChecklist'],
85
- icon: '<path d="M12 3l7 3v5c0 4.4-3 7.6-7 9-4-1.4-7-4.6-7-9V6l7-3Z" stroke-linejoin="round"/><path d="M9 12l2 2 4-4" stroke-linecap="round" stroke-linejoin="round"/>',
86
- },
87
- manualTestsChecklist: {
88
- key: 'manualTestsChecklist', displayName: 'Manual Tests Checklist', description: 'Drafts a manual test checklist for the change. User-visible flows, edge cases, regressions worth clicking through.',
89
- color: 'blue', order: 5, connectsTo: ['manualWebUiTesting'],
90
- icon: '<rect x="6" y="4" width="12" height="17" rx="2"/><path d="M9.5 4V2.8h5V4" stroke-linejoin="round"/><path d="M8.8 12l1.6 1.6L13.4 10" stroke-linecap="round" stroke-linejoin="round"/>',
91
- },
92
- manualWebUiTesting: {
93
- key: 'manualWebUiTesting', displayName: 'Manual web UI testing', description: 'Runs the manual checklist in the live web UI via Playwright. Reports what passed, failed, or blocked.',
94
- color: 'violet', order: 6, connectsTo: ['implementer'],
95
- icon: '<circle cx="12" cy="12" r="9"/><path d="M10 8.5l5 3.5-5 3.5V8.5Z" fill="currentColor" stroke="none"/>',
96
- },
97
- planReviewer: {
98
- key: 'planReviewer', displayName: 'Plan Review', description: 'Reviews the plan against the request and the codebase. Blocking issues bounce it back for a cold re-plan.',
99
- color: 'amber', order: 7, connectsTo: ['planner', 'implementer', 'decomposer'],
100
- icon: '<path d="M10.5 4a6.5 6.5 0 1 0 0 13 6.5 6.5 0 0 0 0-13Z"/><path d="M15.5 15.5L21 21" stroke-linecap="round"/><path d="M7.6 10.3l2 2 3.3-3.6" stroke-linecap="round" stroke-linejoin="round"/>',
101
- },
102
- };
103
-
104
- // mergePalette(agentsResponse) -> ordered Array<{key,displayName,description,color,icon,origin,order}>.
105
- // Prefers the live registry (GET /api/agents -> { agents:[…] } or a bare array);
106
- // falls back to EMBEDDED_AGENTS. Always sorted by .order so the palette is stable.
107
- export function mergePalette(agentsResponse) {
108
- let list = null;
109
- if (Array.isArray(agentsResponse)) list = agentsResponse;
110
- else if (agentsResponse && Array.isArray(agentsResponse.agents)) list = agentsResponse.agents;
111
- if (!list || !list.length) list = Object.values(EMBEDDED_AGENTS);
112
- return list
113
- .map((a) => ({
114
- key: a.key,
115
- displayName: a.displayName || a.key,
116
- description: a.description || '',
117
- color: a.color || 'blue',
118
- icon: a.icon || '',
119
- // Trusted-icon gate: only 'user' is untrusted; the EMBEDDED_AGENTS
120
- // fallback has no origin and is repo-shipped -> 'builtin' is correct.
121
- origin: a.origin === 'user' ? 'user' : 'builtin',
122
- order: typeof a.order === 'number' ? a.order : 99,
123
- domain: typeof a.domain === 'string' && a.domain ? a.domain : 'general',
124
- connectsTo: a.connectsTo === undefined ? '*' : a.connectsTo,
125
- produces: Array.isArray(a.produces) ? a.produces : [],
126
- consumes: Array.isArray(a.consumes) ? a.consumes : [],
127
- optionalConsumes: Array.isArray(a.optionalConsumes) ? a.optionalConsumes : [],
128
- }))
129
- .sort((x, y) => x.order - y.order);
130
- }
131
-
132
- // groupPaletteByDomain(palette, domains) -> ordered [{domain, agents:[...]}].
133
- // Each group = that domain's own agents PLUS every `shared` agent prepended,
134
- // then sorted by .order. Pure: no DOM. `domains` is the ordered header list
135
- // (general last, shared excluded) — see collectDomains / paletteDomains.
136
- export function groupPaletteByDomain(palette, domains) {
137
- const list = Array.isArray(palette) ? palette : [];
138
- const shared = list.filter((a) => a.domain === 'shared');
139
- const byOrder = (x, y) => x.order - y.order;
140
- return (Array.isArray(domains) ? domains : []).map((domain) => ({
141
- domain,
142
- agents: [...shared, ...list.filter((a) => a.domain === domain)].sort(byOrder),
143
- }));
144
- }
145
-
146
- // defaultTopologyFromTemplate(tpl, mk) -> canvas model {steps,feedbacks} with
147
- // FRESH local ids (mk(key) -> {id,key}). The server template's instance ids
148
- // (s*_*) are deliberately discarded: once on the canvas, nodes get throwaway
149
- // local ids and topology() re-stamps contract ids on save. Feedback edges are
150
- // rewired from server ids to the new local ids by walking the same order.
151
- export function defaultTopologyFromTemplate(tpl, mk) {
152
- if (!tpl || !Array.isArray(tpl.steps) || !tpl.steps.length) {
153
- return { steps: [], feedbacks: [] };
154
- }
155
- const remap = {}; // serverId -> localId
156
- const steps = tpl.steps.map((col) =>
157
- col.map((node) => {
158
- const local = mk(node.key);
159
- remap[node.id] = local.id;
160
- return local;
161
- }),
162
- );
163
- const feedbacks = (tpl.feedbacks || [])
164
- .filter((fb) => remap[fb.from] && remap[fb.to])
165
- .map((fb) => ({ from: remap[fb.from], to: remap[fb.to] }));
166
- return { steps, feedbacks };
167
- }
168
-
169
- // Channels a pipeline gets without any producing NODE adjacent on the canvas: the
170
- // user prompt, the shared worktree, the frozen workspace snapshot, and the clarify
171
- // pre-step. Module-local on purpose — this is NOT channels.mjs PRESEEDED_CHANNELS
172
- // (that one lists the validator's value-bearing bus seeds and includes
173
- // plan/checklist; here plan/checklist stay checkable so a producer-less consumer
174
- // of real content still warns, while this no-build browser module keeps zero
175
- // imports from src/core).
176
- const SOFT_PRESEEDED = ['userPrompt', 'code', 'workspace', 'clarify'];
177
-
178
- // canConnect(fromKey, toKey, agents) -> { ok, reason, warn? }.
179
- // Governance (connectsTo) is the HARD gate, exactly as before — and an explicit
180
- // allowlist that admits the target is treated as AUTHOR-CURATED: the soft channel
181
- // check is skipped (e.g. decomposer -> implementer, where the plan flows through
182
- // from upstream via the bus). Only wildcard links get the soft pairwise check:
183
- // when the source produces nothing the target consumes AND the target's required
184
- // inputs are not all pre-seeded, we return ok:true with a `warn` string the UI
185
- // surfaces as a toast.
186
- export function canConnect(fromKey, toKey, agents) {
187
- const from = agents && agents[fromKey];
188
- const ct = from ? from.connectsTo : '*';
189
- if (Array.isArray(ct)) {
190
- if (!ct.includes(toKey)) {
191
- const fn = (from && from.displayName) || fromKey;
192
- const tn = (agents[toKey] && agents[toKey].displayName) || toKey;
193
- return { ok: false, reason: `${fn} can’t connect to ${tn}` };
194
- }
195
- return { ok: true, reason: '' }; // curated allowlist: author vetted this link
196
- }
197
- const to = agents && agents[toKey];
198
- if (from && to && Array.isArray(from.produces) && Array.isArray(to.consumes)
199
- && from.produces.length && to.consumes.length) {
200
- const feeds = from.produces.some((c) => to.consumes.includes(c));
201
- const required = to.consumes.filter((c) =>
202
- !(Array.isArray(to.optionalConsumes) && to.optionalConsumes.includes(c)) &&
203
- !SOFT_PRESEEDED.includes(c));
204
- if (!feeds && required.length) {
205
- const fn = from.displayName || fromKey;
206
- const tn = to.displayName || toKey;
207
- return { ok: true, reason: '', warn: `${fn} produces [${from.produces.join(', ')}] but ${tn} needs [${required.join(', ')}]` };
208
- }
209
- }
210
- return { ok: true, reason: '' };
211
- }