@worca/app 1.3.0 → 1.4.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.
- package/README.md +85 -6
- package/agents/clarify.meta.json +1 -0
- package/agents/memoryDefragmenter.meta.json +2 -1
- package/agents/reviewer.meta.json +60 -0
- package/agents/worca-cc-code-reviewer.md +33 -0
- package/agents/worca-cc-memory-defragmenter.md +5 -3
- package/agents/workspaceScanner.meta.json +1 -0
- package/package.json +14 -10
- package/scripts/git-diff.mjs +25 -0
- package/scripts/gitDiff.meta.json +18 -0
- package/scripts/js-inline.mjs +11 -0
- package/scripts/js.meta.json +22 -0
- package/scripts/py-inline.py +27 -0
- package/scripts/py.meta.json +22 -0
- package/scripts/shell.meta.json +24 -0
- package/skills/worca/SKILL.md +3 -2
- package/src/cli/models.mjs +247 -0
- package/src/cli/render.mjs +72 -4
- package/src/cli/schedule.mjs +494 -0
- package/src/cli/worca-cc.mjs +1001 -22
- package/src/core/agent-registry.mjs +75 -23
- package/src/core/agent-store.mjs +51 -2
- package/src/core/artifacts.mjs +73 -10
- package/src/core/ask/events.mjs +119 -1
- package/src/core/ask/limits.mjs +32 -4
- package/src/core/ask/mcp-stdio.mjs +12 -0
- package/src/core/ask/model-deps.mjs +126 -0
- package/src/core/ask/model-proposal.mjs +370 -0
- package/src/core/ask/models.mjs +12 -0
- package/src/core/ask/policy-deps.mjs +124 -0
- package/src/core/ask/policy-proposal.mjs +363 -0
- package/src/core/ask/prompt.mjs +74 -9
- package/src/core/ask/proposal.mjs +54 -5
- package/src/core/ask/schedule-deps.mjs +83 -0
- package/src/core/ask/schedule-spec.mjs +310 -0
- package/src/core/ask/script-deps.mjs +357 -0
- package/src/core/ask/source-deps.mjs +52 -0
- package/src/core/ask/source-spec.mjs +157 -0
- package/src/core/ask/spawn.mjs +1 -0
- package/src/core/ask/store.mjs +6 -3
- package/src/core/ask/tool-deps.mjs +4 -0
- package/src/core/ask/tools.mjs +657 -37
- package/src/core/ask/turn.mjs +109 -2
- package/src/core/ask-files.mjs +406 -0
- package/src/core/ask-forms.mjs +195 -0
- package/src/core/ask-projection.mjs +72 -0
- package/src/core/bridge/errors.mjs +84 -0
- package/src/core/bridge/provider-ops.mjs +281 -0
- package/src/core/bridge/providers/copilot.mjs +269 -0
- package/src/core/bridge/providers/endpoint.mjs +257 -0
- package/src/core/bridge/registry.mjs +88 -0
- package/src/core/bridge/semaphore.mjs +73 -0
- package/src/core/bridge/server.mjs +184 -0
- package/src/core/bridge/telemetry.mjs +53 -0
- package/src/core/bridge/translate/request.mjs +252 -0
- package/src/core/bridge/translate/response.mjs +82 -0
- package/src/core/bridge/translate/stream.mjs +242 -0
- package/src/core/bridge/upstream.mjs +209 -0
- package/src/core/chat/command-router.mjs +58 -4
- package/src/core/chat/notifier.mjs +14 -1
- package/src/core/chat/renderers.mjs +35 -0
- package/src/core/claude-runner.mjs +126 -19
- package/src/core/config.mjs +212 -31
- package/src/core/cost-budget.mjs +3 -2
- package/src/core/db.mjs +169 -15
- package/src/core/failure-policy.mjs +10 -0
- package/src/core/fs-browse.mjs +16 -4
- package/src/core/git-info.mjs +22 -0
- package/src/core/graph/builtin-workflows.mjs +3 -1
- package/src/core/graph/exec-io.mjs +71 -0
- package/src/core/graph/executor.mjs +139 -70
- package/src/core/graph/human-evidence.mjs +131 -0
- package/src/core/graph/python-probe.mjs +172 -0
- package/src/core/graph/registry-ports.mjs +10 -6
- package/src/core/graph/scheduler.mjs +39 -24
- package/src/core/graph/script-child.mjs +81 -0
- package/src/core/graph/script-runner.mjs +597 -0
- package/src/core/graph/worca_script.py +207 -0
- package/src/core/guardrail-store.mjs +16 -0
- package/src/core/human-backfill.mjs +108 -0
- package/src/core/human-rate.mjs +17 -0
- package/src/core/index-html.mjs +6 -2
- package/src/core/memory-defrag-model.mjs +112 -0
- package/src/core/memory-store.mjs +70 -18
- package/src/core/memory-sync.mjs +22 -11
- package/src/core/metrics/read.mjs +4 -1
- package/src/core/metrics/record.mjs +50 -2
- package/src/core/metrics/sync.mjs +6 -4
- package/src/core/model-env.mjs +149 -0
- package/src/core/model-test.mjs +14 -1
- package/src/core/notifications.mjs +128 -0
- package/src/core/onboarding.mjs +8 -2
- package/src/core/orchestrator.mjs +357 -26
- package/src/core/phases.mjs +95 -6
- package/src/core/plugin-api.mjs +24 -7
- package/src/core/plugin-manifest.mjs +184 -18
- package/src/core/plugin-models.mjs +1 -0
- package/src/core/plugin-script-cases.mjs +118 -0
- package/src/core/plugin-store.mjs +163 -17
- package/src/core/plugin-workflows.mjs +71 -17
- package/src/core/policy/cache.mjs +116 -0
- package/src/core/policy/effective.mjs +175 -0
- package/src/core/policy/gate.mjs +91 -0
- package/src/core/policy/local.mjs +145 -0
- package/src/core/policy/registry.mjs +330 -0
- package/src/core/policy/scope.mjs +61 -0
- package/src/core/policy/state.mjs +79 -0
- package/src/core/policy/sync.mjs +513 -0
- package/src/core/protocol.mjs +43 -0
- package/src/core/run-harness.mjs +421 -72
- package/src/core/scheduler.mjs +980 -0
- package/src/core/script-bench.mjs +628 -0
- package/src/core/script-registry.mjs +116 -0
- package/src/core/script-store.mjs +563 -0
- package/src/core/settings.mjs +489 -14
- package/src/core/stats.mjs +33 -2
- package/src/core/workflow-export.mjs +94 -3
- package/src/core/workflow-share.mjs +67 -18
- package/src/core/workflows.mjs +47 -11
- package/src/core/workspaces.mjs +18 -12
- package/src/shared/forms/answer.mjs +164 -0
- package/src/shared/forms/catalog.mjs +91 -0
- package/src/shared/forms/form-def.mjs +290 -0
- package/src/shared/forms/layout.mjs +67 -0
- package/src/shared/forms/paths.mjs +47 -0
- package/src/shared/forms/project.mjs +309 -0
- package/src/shared/forms/schema.mjs +205 -0
- package/src/shared/graph/agent-meta.mjs +55 -5
- package/src/shared/graph/constants.mjs +14 -2
- package/src/shared/graph/flow-layout.mjs +2 -1
- package/src/shared/graph/isomorphic.mjs +5 -3
- package/src/shared/graph/manifest.mjs +22 -13
- package/src/shared/graph/ports.mjs +45 -19
- package/src/shared/graph/script-cases.mjs +257 -0
- package/src/shared/graph/script-icons.mjs +46 -0
- package/src/shared/graph/script-infer.mjs +259 -0
- package/src/shared/graph/script-meta.mjs +408 -0
- package/src/shared/graph/script-templates.mjs +201 -0
- package/src/shared/graph/template.mjs +4 -4
- package/src/shared/graph/validate.mjs +89 -16
- package/src/shared/human-estimate.mjs +100 -0
- package/src/shared/schedule/recurrence.mjs +353 -0
- package/src/shared/team-metrics/aggregate.mjs +51 -11
- package/{scripts → tools}/install.mjs +3 -3
- package/ui/public/app.js +4390 -683
- package/ui/public/artifact-picker.mjs +189 -0
- package/ui/public/ask/dom.mjs +121 -0
- package/ui/public/ask/form-preview.mjs +55 -0
- package/ui/public/ask/form-renderer.mjs +250 -0
- package/ui/public/ask/registry.mjs +53 -0
- package/ui/public/ask/widgets-display.mjs +370 -0
- package/ui/public/ask/widgets-input.mjs +624 -0
- package/ui/public/ask/widgets-layout.mjs +90 -0
- package/ui/public/ask-panel.mjs +401 -27
- package/ui/public/ask-run-card.mjs +1 -1
- package/ui/public/bridge-view.mjs +694 -0
- package/ui/public/chat-settings-view.mjs +24 -0
- package/ui/public/code-editor.mjs +181 -0
- package/ui/public/getting-started.mjs +34 -7
- package/ui/public/graph/composer.mjs +138 -10
- package/ui/public/graph/inspector.mjs +61 -58
- package/ui/public/graph/palette.mjs +27 -9
- package/ui/public/graph/run-decor.mjs +34 -17
- package/ui/public/graph/run-hosts.mjs +7 -1
- package/ui/public/graph/save-dialog.mjs +3 -0
- package/ui/public/graph/view.mjs +23 -7
- package/ui/public/guardrails-view.mjs +15 -3
- package/ui/public/guide-spot.mjs +87 -9
- package/ui/public/index.html +480 -141
- package/ui/public/memory-view.mjs +22 -4
- package/ui/public/models-view.mjs +162 -17
- package/ui/public/node-tunables.mjs +33 -4
- package/ui/public/plugins-view.mjs +23 -1
- package/ui/public/results-view.mjs +4 -2
- package/ui/public/schedule-sheet.mjs +430 -0
- package/ui/public/schedules-view.mjs +432 -0
- package/ui/public/script-bench-view.mjs +1154 -0
- package/ui/public/script-forms.mjs +282 -0
- package/ui/public/script-wizard.mjs +529 -0
- package/ui/public/scripts-view.mjs +868 -0
- package/ui/public/stats-view.mjs +159 -52
- package/ui/public/style.css +1461 -44
- package/ui/public/team-metrics-surfaces.mjs +77 -16
- package/ui/public/team-metrics-view.mjs +68 -5
- package/ui/public/team-policy-view.mjs +1402 -0
- package/ui/public/ui-level.mjs +237 -0
- package/ui/server.mjs +1827 -73
package/ui/public/guide-spot.mjs
CHANGED
|
@@ -2,8 +2,11 @@
|
|
|
2
2
|
// The guided click (docs/getting-started.md): scrim-dim the page, keep ONE real
|
|
3
3
|
// control lit and interactive above it, ring it, say why in one balloon.
|
|
4
4
|
// Action-driven, never narrated — the target's real click is what advances or
|
|
5
|
-
// ends a guide (the caller's onTargetClick);
|
|
6
|
-
// (
|
|
5
|
+
// ends a guide (the caller's onTargetClick); Esc and Skip dismiss (onDismiss); a
|
|
6
|
+
// click on the scrim only nudges (one pulse of ring + balloon), so a stray click
|
|
7
|
+
// never ends a guide. A hop that only explains (the canvas, a panel) or whose state is
|
|
8
|
+
// already there gets a Next button (onNext) so the user can move on without
|
|
9
|
+
// touching anything. Soft-block: nothing here can trap the user.
|
|
7
10
|
//
|
|
8
11
|
// Layering (style.css .guide-*): `spotlight` sits above the Ask dock (40) and
|
|
9
12
|
// below every .viewer-modal (50) — a dialog that opens on the target's click
|
|
@@ -16,6 +19,8 @@
|
|
|
16
19
|
|
|
17
20
|
const ATTACH_TRIES = 120; // ~2 s at 60 fps: a view's list may still be fetching
|
|
18
21
|
const REACQUIRE_FRAMES = 60; // ~1 s: how long a vanished control may take to be repainted
|
|
22
|
+
const GLIDE_MS = 2500; // how long the guide's own smooth scroll may still be emitting scroll events
|
|
23
|
+
const BRING_EVERY = 1200; // ms between two re-scrolls of a control the page carried out of view
|
|
19
24
|
|
|
20
25
|
const frame = (win) => (typeof win.requestAnimationFrame === 'function'
|
|
21
26
|
? (fn) => win.requestAnimationFrame(fn)
|
|
@@ -47,13 +52,15 @@ function visible(el) {
|
|
|
47
52
|
* @param {number} [o.tries] attach retries before giving up (→ onDismiss)
|
|
48
53
|
* @param {() => void} o.onDismiss
|
|
49
54
|
* @param {() => void} o.onTargetClick
|
|
55
|
+
* @param {() => void} [o.onNext] when given, a Next button sits beside Skip and calls it
|
|
56
|
+
* @param {string} [o.nextLabel] its label (default "Next")
|
|
50
57
|
* @param {Document} [o.doc]
|
|
51
58
|
* @param {Window} [o.win]
|
|
52
59
|
* @returns {{destroy:() => void, layer:Element}}
|
|
53
60
|
*/
|
|
54
61
|
export function createGuideSpot({
|
|
55
62
|
target, text, mode = 'spotlight', lift = [], tries = ATTACH_TRIES,
|
|
56
|
-
onDismiss, onTargetClick, doc = globalThis.document, win = globalThis.window,
|
|
63
|
+
onDismiss, onTargetClick, onNext = null, nextLabel = 'Next', doc = globalThis.document, win = globalThis.window,
|
|
57
64
|
}) {
|
|
58
65
|
const targets = Array.isArray(target) ? target : [target];
|
|
59
66
|
const texts = Array.isArray(text) ? text : [text];
|
|
@@ -70,7 +77,10 @@ export function createGuideSpot({
|
|
|
70
77
|
if (mode === 'spotlight') {
|
|
71
78
|
scrim = doc.createElement('div');
|
|
72
79
|
scrim.className = 'guide-scrim';
|
|
73
|
-
|
|
80
|
+
// A click beside the lit control is swallowed, never an exit: a stray click used to end
|
|
81
|
+
// the guide silently, which reads as a bug. The ring and balloon pulse once to say
|
|
82
|
+
// "here" instead. Skip and Esc remain the exits.
|
|
83
|
+
scrim.addEventListener('click', () => nudge());
|
|
74
84
|
layer.appendChild(scrim);
|
|
75
85
|
}
|
|
76
86
|
const ring = doc.createElement('div');
|
|
@@ -88,12 +98,34 @@ export function createGuideSpot({
|
|
|
88
98
|
skip.className = 'guide-skip';
|
|
89
99
|
skip.textContent = 'Skip';
|
|
90
100
|
skip.addEventListener('click', () => dismiss());
|
|
91
|
-
|
|
101
|
+
const actions = doc.createElement('div');
|
|
102
|
+
actions.className = 'guide-actions';
|
|
103
|
+
if (typeof onNext === 'function') {
|
|
104
|
+
const next = doc.createElement('button');
|
|
105
|
+
next.type = 'button';
|
|
106
|
+
next.className = 'guide-next';
|
|
107
|
+
next.textContent = nextLabel || 'Next';
|
|
108
|
+
// The caller re-derives the hop and replaces this layer; nothing is dismissed here.
|
|
109
|
+
next.addEventListener('click', () => { if (alive) onNext(); });
|
|
110
|
+
actions.appendChild(next);
|
|
111
|
+
}
|
|
112
|
+
actions.appendChild(skip);
|
|
113
|
+
balloon.append(line, actions);
|
|
92
114
|
layer.append(ring, balloon);
|
|
93
115
|
doc.body.appendChild(layer);
|
|
94
116
|
|
|
95
117
|
const onKey = (e) => { if (e.key === 'Escape') { e.preventDefault(); dismiss(); } };
|
|
96
118
|
doc.addEventListener('keydown', onKey);
|
|
119
|
+
// The user's own scrolling (wheel, touch, paging keys, a scrollbar drag — any scroll that is not
|
|
120
|
+
// the tail of the guide's own glide) — after it, the guide never re-scrolls.
|
|
121
|
+
let userScrolled = false;
|
|
122
|
+
let lastBring = 0;
|
|
123
|
+
const onUserScroll = (e) => {
|
|
124
|
+
if (e.type === 'keydown' && !['ArrowDown', 'ArrowUp', 'PageDown', 'PageUp', 'Home', 'End', ' '].includes(e.key)) return;
|
|
125
|
+
if (e.type === 'scroll' && Date.now() - lastBring < GLIDE_MS) return;
|
|
126
|
+
userScrolled = true;
|
|
127
|
+
};
|
|
128
|
+
for (const t of ['wheel', 'touchmove', 'keydown', 'scroll']) doc.addEventListener(t, onUserScroll, { passive: true, capture: true });
|
|
97
129
|
|
|
98
130
|
function destroy() {
|
|
99
131
|
if (!alive) return;
|
|
@@ -101,6 +133,7 @@ export function createGuideSpot({
|
|
|
101
133
|
caf(handle);
|
|
102
134
|
cleanup();
|
|
103
135
|
doc.removeEventListener('keydown', onKey);
|
|
136
|
+
for (const t of ['wheel', 'touchmove', 'keydown', 'scroll']) doc.removeEventListener(t, onUserScroll, { capture: true });
|
|
104
137
|
layer.remove();
|
|
105
138
|
}
|
|
106
139
|
function dismiss() {
|
|
@@ -108,6 +141,18 @@ export function createGuideSpot({
|
|
|
108
141
|
destroy();
|
|
109
142
|
if (onDismiss) onDismiss();
|
|
110
143
|
}
|
|
144
|
+
/** Draw the eye to the lit control: one pulse of the ring and the balloon (restarted on repeat). */
|
|
145
|
+
function nudge() {
|
|
146
|
+
if (!alive) return;
|
|
147
|
+
for (const el of [ring, balloon]) {
|
|
148
|
+
el.classList.remove('nudge');
|
|
149
|
+
void el.offsetWidth; // restart the animation when clicked again mid-pulse
|
|
150
|
+
el.classList.add('nudge');
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
const onNudgeEnd = (e) => { e.currentTarget.classList.remove('nudge'); };
|
|
154
|
+
ring.addEventListener('animationend', onNudgeEnd);
|
|
155
|
+
balloon.addEventListener('animationend', onNudgeEnd);
|
|
111
156
|
|
|
112
157
|
/** Centre the balloon under its target, clamped to the viewport, arrow aimed
|
|
113
158
|
* at the target's centre WITHIN the balloon; above the target when there is
|
|
@@ -126,10 +171,24 @@ export function createGuideSpot({
|
|
|
126
171
|
const centre = rect.left + rect.width / 2;
|
|
127
172
|
const left = Math.max(8, Math.min(centre - box.width / 2, Math.max(8, vw - box.width - 8)));
|
|
128
173
|
const gap = 14;
|
|
129
|
-
|
|
174
|
+
// "Fits" means inside the viewport, not merely on that side of the control: a control
|
|
175
|
+
// scrolled out of view has no room on either side.
|
|
176
|
+
const fitsBelow = vh > 0 && rect.bottom + gap >= 8 && rect.bottom + gap + box.height <= vh - 8;
|
|
177
|
+
const fitsAbove = rect.top - gap - box.height >= 8 && rect.top - gap <= vh - 8;
|
|
178
|
+
// Neither edge has room (a run card taller than the window): the balloon is PINNED inside
|
|
179
|
+
// the viewport, over the target, arrow off — never parked off-screen where "the guide is
|
|
180
|
+
// stuck" is all the user can see.
|
|
181
|
+
const pinned = vh > 0 && !fitsBelow && !fitsAbove;
|
|
182
|
+
const above = !pinned && !fitsBelow && fitsAbove;
|
|
130
183
|
balloon.classList.toggle('above', above);
|
|
184
|
+
balloon.classList.toggle('pinned', pinned);
|
|
131
185
|
balloon.style.left = `${left}px`;
|
|
132
|
-
|
|
186
|
+
if (pinned) {
|
|
187
|
+
const top = Math.max(16, Math.min(rect.top + gap, vh - box.height - 16));
|
|
188
|
+
balloon.style.top = `${top}px`;
|
|
189
|
+
} else {
|
|
190
|
+
balloon.style.top = above ? `${rect.top - box.height - gap}px` : `${rect.bottom + gap}px`;
|
|
191
|
+
}
|
|
133
192
|
balloon.style.setProperty('--arrow-x', `${Math.max(16, Math.min(centre - left, box.width - 16))}px`);
|
|
134
193
|
}
|
|
135
194
|
|
|
@@ -149,6 +208,13 @@ export function createGuideSpot({
|
|
|
149
208
|
return;
|
|
150
209
|
}
|
|
151
210
|
el.classList.add('guide-target');
|
|
211
|
+
// The elevation needs a positioned box. A static control gets position:relative;
|
|
212
|
+
// one that is already positioned (the Composer's floating rail is absolute) keeps
|
|
213
|
+
// its own position — forcing relative would pull it out of place.
|
|
214
|
+
try {
|
|
215
|
+
const pos = win.getComputedStyle(el).position;
|
|
216
|
+
if (!pos || pos === 'static') el.classList.add('guide-target-static');
|
|
217
|
+
} catch { el.classList.add('guide-target-static'); }
|
|
152
218
|
line.textContent = texts[which] ?? texts[0] ?? '';
|
|
153
219
|
layer.dataset.target = targets[which];
|
|
154
220
|
// The ring follows the control's own corner radius (a pill stays a pill).
|
|
@@ -168,10 +234,17 @@ export function createGuideSpot({
|
|
|
168
234
|
}
|
|
169
235
|
// Glide to the control (the ring follows it per frame, so the eye is led
|
|
170
236
|
// down the page); reduced motion jumps.
|
|
237
|
+
let bring = () => {};
|
|
171
238
|
if (typeof el.scrollIntoView === 'function') {
|
|
172
239
|
let reduced = false;
|
|
173
240
|
try { reduced = !!(win.matchMedia && win.matchMedia('(prefers-reduced-motion: reduce)').matches); } catch { /* jsdom */ }
|
|
174
|
-
|
|
241
|
+
// A control taller than most of the window is brought to its top, not its middle (which
|
|
242
|
+
// would leave its head — and the balloon — above the fold).
|
|
243
|
+
let block = 'center';
|
|
244
|
+
try { const vh = win.innerHeight || 0; if (vh && el.getBoundingClientRect().height > vh * 0.6) block = 'start'; } catch { /* jsdom */ }
|
|
245
|
+
bring = () => { lastBring = Date.now(); try { el.scrollIntoView({ block, inline: 'nearest', behavior: reduced ? 'auto' : 'smooth' }); } catch { /* jsdom */ } };
|
|
246
|
+
userScrolled = false;
|
|
247
|
+
bring();
|
|
175
248
|
}
|
|
176
249
|
const onClick = () => {
|
|
177
250
|
if (!alive) return;
|
|
@@ -198,12 +271,17 @@ export function createGuideSpot({
|
|
|
198
271
|
return;
|
|
199
272
|
}
|
|
200
273
|
const b = el.getBoundingClientRect();
|
|
274
|
+
// A view that keeps settling (a run list re-sorting its cards, a log growing) can carry
|
|
275
|
+
// the control ENTIRELY out of view after the glide: bring it back — throttled, so a glide
|
|
276
|
+
// in flight is not restarted every frame — but never over the user's own scrolling.
|
|
277
|
+
const vh = win.innerHeight || 0;
|
|
278
|
+
if (!userScrolled && vh && (b.bottom < 0 || b.top > vh) && Date.now() - lastBring > BRING_EVERY) bring();
|
|
201
279
|
const key = `${b.top}|${b.left}|${b.width}|${b.height}`;
|
|
202
280
|
if (key !== last) { last = key; place(b); }
|
|
203
281
|
handle = raf(track);
|
|
204
282
|
};
|
|
205
283
|
cleanup = () => {
|
|
206
|
-
el.classList.remove('guide-target');
|
|
284
|
+
el.classList.remove('guide-target', 'guide-target-static');
|
|
207
285
|
for (const a of lifted) a.classList.remove('guide-lift', 'guide-lift-static');
|
|
208
286
|
el.removeEventListener('click', onClick);
|
|
209
287
|
};
|