@worca/app 1.3.0 → 1.4.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.
- 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
|
@@ -80,6 +80,7 @@ export function weekStartMs(ms) {
|
|
|
80
80
|
|
|
81
81
|
const startOf = (r) => Date.parse(r.startedAt);
|
|
82
82
|
const usdOf = (r) => (Number.isFinite(r?.cost?.usd) ? r.cost.usd : 0);
|
|
83
|
+
const hoursOf = (r) => (Number.isFinite(r?.human?.hours) ? r.human.hours : 0);
|
|
83
84
|
const isNum = (v) => typeof v === 'number' && Number.isFinite(v);
|
|
84
85
|
const sum = (a) => a.reduce((s, x) => s + x, 0);
|
|
85
86
|
const round2 = (v) => Math.round(v * 100) / 100;
|
|
@@ -127,18 +128,26 @@ export function applyFilter(records, filter = {}) {
|
|
|
127
128
|
return records.filter((r) => active.every(([dim, key]) => DIMENSIONS[dim](r).some((k) => k.key === key)));
|
|
128
129
|
}
|
|
129
130
|
|
|
130
|
-
function computeKpis(rs, now) {
|
|
131
|
+
function computeKpis(rs, now, humanRateUsd = 0) {
|
|
131
132
|
const n = rs.length;
|
|
132
133
|
const count = (res) => rs.filter((r) => r.result === res).length;
|
|
133
134
|
const usd = sum(rs.map(usdOf));
|
|
135
|
+
const hours = round2(sum(rs.map(hoursOf)));
|
|
134
136
|
const paired = rs.filter((r) => isNum(r.wallMs) && isNum(r.activeMs));
|
|
135
|
-
|
|
137
|
+
// Autonomy = active ÷ (wall − paused): a run parked on a pause or a crash was not waiting on a
|
|
138
|
+
// human, so its parked time leaves the denominator. `pausedMs` is additive — records pushed
|
|
139
|
+
// before it existed park nothing.
|
|
140
|
+
const wallSum = sum(paired.map((r) => Math.max(0, r.wallMs - (isNum(r.pausedMs) ? r.pausedMs : 0))));
|
|
136
141
|
const withPr = rs.filter((r) => r.pr && (r.pr.url || r.pr.number != null));
|
|
137
142
|
const reviews = rs.map((r) => r.cycles?.review).filter(isNum);
|
|
138
143
|
const d = new Date(now);
|
|
139
144
|
const monthStart = Date.UTC(d.getUTCFullYear(), d.getUTCMonth(), 1);
|
|
140
145
|
return {
|
|
141
146
|
spendUsd: round2(usd),
|
|
147
|
+
// Human hours (money-saved design §9.2): records without `human` count 0 h; `humanRuns` gates the tile.
|
|
148
|
+
humanHours: hours,
|
|
149
|
+
humanRuns: rs.filter((r) => Number.isFinite(r?.human?.hours)).length,
|
|
150
|
+
savedUsd: round2(hours * humanRateUsd - usd),
|
|
142
151
|
spendThisMonthUsd: round2(sum(rs.filter((r) => startOf(r) >= monthStart).map(usdOf))),
|
|
143
152
|
runs: n,
|
|
144
153
|
done: count('done'), failed: count('failed'), stopped: count('stopped'),
|
|
@@ -155,14 +164,26 @@ function computeKpis(rs, now) {
|
|
|
155
164
|
reviewCyclesMean: reviews.length ? round1(sum(reviews) / reviews.length) : null,
|
|
156
165
|
convergeInOneRate: reviews.length ? reviews.filter((c) => c <= 1).length / reviews.length : null,
|
|
157
166
|
filesChanged: sum(rs.map((r) => r.git?.filesChanged).filter(isNum)),
|
|
167
|
+
// Team policy (team-policy design §10): runs that went past a team cap (continued past, or
|
|
168
|
+
// exceeded under warn / unattended) or picked something off-policy. Additive; policy-less
|
|
169
|
+
// records count nothing.
|
|
170
|
+
offPolicyRuns: rs.filter((r) => policyOverrides(r) + policyDeviations(r) > 0).length,
|
|
171
|
+
capOverrides: sum(rs.map(policyOverrides)),
|
|
172
|
+
deviations: sum(rs.map(policyDeviations)),
|
|
173
|
+
policyRuns: rs.filter((r) => r.policy && r.policy.home).length,
|
|
158
174
|
};
|
|
159
175
|
}
|
|
160
176
|
|
|
177
|
+
const policyOverrides = (r) => (r.policy && r.policy.home ? (Array.isArray(r.policy.overrides) ? r.policy.overrides.length : 0) + (Array.isArray(r.policy.exceeded) ? r.policy.exceeded.length : 0) : 0);
|
|
178
|
+
const policyDeviations = (r) => (r.policy && r.policy.home && Array.isArray(r.policy.deviations) ? r.policy.deviations.length : 0);
|
|
179
|
+
|
|
161
180
|
const pct = (cur, prev) => (isNum(cur) && isNum(prev) && prev > 0 ? (cur - prev) / prev : null);
|
|
162
181
|
|
|
163
182
|
function deltas(k, p) {
|
|
164
183
|
return {
|
|
165
184
|
spendPct: pct(k.spendUsd, p.spendUsd),
|
|
185
|
+
humanHoursPct: pct(k.humanHours, p.humanHours),
|
|
186
|
+
savedPct: pct(k.savedUsd, p.savedUsd),
|
|
166
187
|
runsPct: pct(k.runs, p.runs),
|
|
167
188
|
costPerRunPct: pct(k.costPerRunUsd, p.costPerRunUsd),
|
|
168
189
|
durationPct: pct(k.durationMedianMs, p.durationMedianMs),
|
|
@@ -175,9 +196,11 @@ function breakdown(rs, dim) {
|
|
|
175
196
|
const rows = new Map();
|
|
176
197
|
for (const r of rs) {
|
|
177
198
|
for (const k of DIMENSIONS[dim](r)) {
|
|
178
|
-
const row = rows.get(k.key) || { key: k.key, label: k.label, sub: k.sub ?? null, runs: 0, usd: 0, done: 0, reviews: [], filesChanged: 0, filesUnknown: 0 };
|
|
199
|
+
const row = rows.get(k.key) || { key: k.key, label: k.label, sub: k.sub ?? null, runs: 0, usd: 0, done: 0, reviews: [], filesChanged: 0, filesUnknown: 0, overrides: 0, offPolicy: 0 };
|
|
179
200
|
row.runs += 1;
|
|
180
201
|
row.usd += usdOf(r); // "a run touching two projects counts in both"
|
|
202
|
+
row.overrides += policyOverrides(r); // team caps continued past / exceeded (team policy §10)
|
|
203
|
+
row.offPolicy += policyDeviations(r);
|
|
181
204
|
if (r.result === 'done') row.done += 1;
|
|
182
205
|
if (isNum(r.cycles?.review)) row.reviews.push(r.cycles.review);
|
|
183
206
|
// A key that carries its own count (a touched member) uses it; every other dimension is
|
|
@@ -207,6 +230,8 @@ function breakdown(rs, dim) {
|
|
|
207
230
|
// null when no run in the row carries a count: the cell shows "–", never a wrong number.
|
|
208
231
|
filesChanged: row.filesUnknown === row.runs ? null : row.filesChanged,
|
|
209
232
|
filesUnknown: row.filesUnknown,
|
|
233
|
+
overrides: row.overrides,
|
|
234
|
+
offPolicy: row.offPolicy,
|
|
210
235
|
isNone: row.key === NONE,
|
|
211
236
|
}))
|
|
212
237
|
// Projects order by what the table shows (runs touched, then files); every other dimension by spend.
|
|
@@ -271,11 +296,17 @@ export function safeHttpUrl(u) {
|
|
|
271
296
|
try { const x = new URL(u); return x.protocol === 'https:' || x.protocol === 'http:' ? x.href : null; } catch { return null; }
|
|
272
297
|
}
|
|
273
298
|
|
|
274
|
-
function toRunRow(r) {
|
|
299
|
+
function toRunRow(r, humanRateUsd = 0) {
|
|
300
|
+
const usd = usdOf(r);
|
|
301
|
+
// Money saved (design §9.2) per run: null when the record carries no `human` (pre-v33 pushes),
|
|
302
|
+
// so the row prints "—" rather than claiming "−$cost" was saved. Same gate as the KPI tile.
|
|
303
|
+
const humanHours = isNum(r.human?.hours) ? r.human.hours : null;
|
|
275
304
|
return {
|
|
276
305
|
id: r.id, title: r.title ?? '(untitled)', startedAt: r.startedAt,
|
|
277
306
|
workflow: r.workflow?.name ?? r.workflow?.id ?? null, result: r.result,
|
|
278
|
-
usd
|
|
307
|
+
usd, wallMs: isNum(r.wallMs) ? r.wallMs : null, activeMs: isNum(r.activeMs) ? r.activeMs : null,
|
|
308
|
+
pausedMs: isNum(r.pausedMs) ? r.pausedMs : null,
|
|
309
|
+
humanHours, savedUsd: humanHours == null ? null : round2(humanHours * humanRateUsd - usd),
|
|
279
310
|
reviewCycles: isNum(r.cycles?.review) ? r.cycles.review : null,
|
|
280
311
|
pr: r.pr && (r.pr.url || r.pr.number != null) ? { number: Number.isInteger(r.pr.number) ? r.pr.number : null, url: safeHttpUrl(r.pr.url) } : null,
|
|
281
312
|
actor: r.actor ?? null,
|
|
@@ -283,6 +314,15 @@ function toRunRow(r) {
|
|
|
283
314
|
projects: r.target?.kind === 'workspace'
|
|
284
315
|
? (Array.isArray(r.target.touched) ? r.target.touched.filter((p) => typeof p === 'string') : [])
|
|
285
316
|
: [r.target?.project].filter((p) => typeof p === 'string' && p),
|
|
317
|
+
// Team policy (§10): only on a run recorded under a policy, so policy-less rows keep their shape.
|
|
318
|
+
...(r.policy && r.policy.home ? { policy: {
|
|
319
|
+
home: r.policy.home,
|
|
320
|
+
overrides: Array.isArray(r.policy.overrides) ? r.policy.overrides : [],
|
|
321
|
+
exceeded: Array.isArray(r.policy.exceeded) ? r.policy.exceeded : [],
|
|
322
|
+
deviations: Array.isArray(r.policy.deviations) ? r.policy.deviations : [],
|
|
323
|
+
unattended: r.policy.unattended === true,
|
|
324
|
+
reason: typeof r.policy.reason === 'string' ? r.policy.reason : null,
|
|
325
|
+
} } : {}),
|
|
286
326
|
};
|
|
287
327
|
}
|
|
288
328
|
|
|
@@ -290,15 +330,15 @@ function toRunRow(r) {
|
|
|
290
330
|
* @param {object[]} records v1 records (already parsed; unknown v / malformed already dropped)
|
|
291
331
|
* @param {{range?:string, from?:string|null, to?:string|null, groupBy?:string, filter?:object, now?:number}} [opts]
|
|
292
332
|
*/
|
|
293
|
-
export function aggregate(records, { range = 'this-month', from = null, to = null, groupBy = 'workflow', filter = {}, now = Date.now() } = {}) {
|
|
333
|
+
export function aggregate(records, { range = 'this-month', from = null, to = null, groupBy = 'workflow', filter = {}, now = Date.now(), humanRateUsd = 0 } = {}) {
|
|
294
334
|
if (!GROUP_BYS.includes(groupBy)) throw new RangeError(`unknown groupBy "${groupBy}" (expected ${GROUP_BYS.join(' | ')})`);
|
|
295
335
|
const win = resolveRange(range, { now, from, to });
|
|
296
336
|
const usable = (records || []).filter((r) => r && Number.isFinite(startOf(r)));
|
|
297
337
|
const filtered = applyFilter(usable, filter);
|
|
298
338
|
const inWin = (s, e) => (r) => (s == null || startOf(r) >= s) && (e == null || startOf(r) < e);
|
|
299
339
|
const inRange = filtered.filter(inWin(win.startMs, win.endMs));
|
|
300
|
-
const kpis = computeKpis(inRange, now);
|
|
301
|
-
const prevKpis = win.prevStartMs == null ? null : computeKpis(filtered.filter(inWin(win.prevStartMs, win.prevEndMs)), now);
|
|
340
|
+
const kpis = computeKpis(inRange, now, humanRateUsd);
|
|
341
|
+
const prevKpis = win.prevStartMs == null ? null : computeKpis(filtered.filter(inWin(win.prevStartMs, win.prevEndMs)), now, humanRateUsd);
|
|
302
342
|
const hasActor = inRange.some((r) => r.actor);
|
|
303
343
|
const hasWorkspace = inRange.some((r) => r.target?.kind === 'workspace');
|
|
304
344
|
return {
|
|
@@ -312,12 +352,12 @@ export function aggregate(records, { range = 'this-month', from = null, to = nul
|
|
|
312
352
|
project: hasWorkspace ? breakdown(inRange, 'project') : null,
|
|
313
353
|
models: breakdown(inRange, 'models'),
|
|
314
354
|
},
|
|
315
|
-
runs: [...inRange].sort((a, b) => startOf(b) - startOf(a)).map(toRunRow),
|
|
355
|
+
runs: [...inRange].sort((a, b) => startOf(b) - startOf(a)).map((r) => toRunRow(r, humanRateUsd)),
|
|
316
356
|
totalRecords: usable.length,
|
|
317
357
|
};
|
|
318
358
|
}
|
|
319
359
|
|
|
320
|
-
export const CSV_COLUMNS = Object.freeze(['startedAt', 'title', 'workflow', 'result', 'costUsd', 'wallMs', 'activeMs', 'reviewCycles', 'prNumber', 'prUrl', 'actor', 'source', 'projects', 'id']);
|
|
360
|
+
export const CSV_COLUMNS = Object.freeze(['startedAt', 'title', 'workflow', 'result', 'costUsd', 'humanHours', 'savedUsd', 'wallMs', 'activeMs', 'pausedMs', 'reviewCycles', 'prNumber', 'prUrl', 'actor', 'source', 'projects', 'id']);
|
|
321
361
|
|
|
322
362
|
function csvCell(v) {
|
|
323
363
|
if (v == null) return '';
|
|
@@ -331,7 +371,7 @@ export function toCsv(runRows) {
|
|
|
331
371
|
const lines = [CSV_COLUMNS.join(',')];
|
|
332
372
|
for (const r of runRows) {
|
|
333
373
|
lines.push([
|
|
334
|
-
r.startedAt, r.title, r.workflow, r.result, r.usd, r.wallMs, r.activeMs, r.reviewCycles,
|
|
374
|
+
r.startedAt, r.title, r.workflow, r.result, r.usd, r.humanHours, r.savedUsd, r.wallMs, r.activeMs, r.pausedMs, r.reviewCycles,
|
|
335
375
|
r.pr?.number, r.pr?.url, r.actor, r.source, (r.projects || []).join(' '), r.id,
|
|
336
376
|
].map(csvCell).join(','));
|
|
337
377
|
}
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
//
|
|
2
|
+
// tools/install.mjs
|
|
3
3
|
//
|
|
4
4
|
// Copy the orchestrator agents and the /worca skill into a target project's
|
|
5
5
|
// .claude directory so that opening Claude Code there lets the user run:
|
|
6
6
|
// /worca <prompt>
|
|
7
7
|
//
|
|
8
8
|
// Usage:
|
|
9
|
-
// node
|
|
9
|
+
// node tools/install.mjs <targetDir> [--force]
|
|
10
10
|
//
|
|
11
11
|
// - agents/*.md -> <targetDir>/.claude/agents/
|
|
12
12
|
// - skills/worca/** -> <targetDir>/.claude/skills/worca/
|
|
@@ -39,7 +39,7 @@ function parseArgs(argv) {
|
|
|
39
39
|
const HELP = `install — copy orchestrator agents + /worca skill into a project
|
|
40
40
|
|
|
41
41
|
Usage:
|
|
42
|
-
node
|
|
42
|
+
node tools/install.mjs <targetDir> [--force]
|
|
43
43
|
|
|
44
44
|
Copies:
|
|
45
45
|
agents/*.md -> <targetDir>/.claude/agents/
|